0

I'm trying to develop a set of form components in Angular 8 using BootStrap but there is a strange behavior.

Following html works perfectly:

<div class="form-group row">
    <label for="input01" class="col-2 col-form-label">First Name</label>
    <div class="col-4">
        <input type="text" class="form-control" id="input01" placeholder="First Name">
  </div>
    <label for="input01" class="col-2 col-form-label">Last Name</label>
    <div class="col-4">
        <input type="text" class="form-control" id="input01" placeholder="Last Name">
  </div>
</div>

I can see two inputs with its labels side by side (2+4 columns for each input/label).

If I take this snipet and encapsulates it in a component:

<label for="input01" class="col-2 col-form-label">First Name</label>
<div class="col-4">
    <input type="text" class="form-control" id="input01" placeholder="First Name">
</div>

And use it as following:

<div class="form-group row">
  <app-input-text></app-input-text>
  <app-input-text></app-input-text>
</div>

It seems to be shrinked.

Please note it is the same code but encapsulated in a component.

What's wrong?

PS: Here is the StackBlitz running code: https://stackblitz.com/edit/angular-g3zxg3

Thanks in advance.

8
  • 2
    Bootstrap needs the .col to be a direct child of the .row. But it's not, since you have app-input-text in the middle. Commented Dec 27, 2019 at 19:46
  • Yes, you're right but how do I create multi and single column input forms if I'm stuck on this rule? I mean, if I need to create a single line field (12), I'll wrap app-input-text in a single row, if I need two inputs, I can do what I did in the sample and so on... Commented Dec 27, 2019 at 19:54
  • Use a .row inside the component template, with two children .col-4 and .col-8. In the parent use a .row with two children.col-6. Commented Dec 27, 2019 at 19:56
  • It works but I'll loose flexibility because my intention is to allow component user to set the width of label and input. Commented Dec 27, 2019 at 20:04
  • And why couldn't you do that? You'll actually gain in flexibility since your component can be used anywhere, and not only in a .row like what you have. Commented Dec 27, 2019 at 20:06

1 Answer 1

2

You can remove wrapping tags with some work arounds. One is using directives or attribute selectors or using template injection like below:

Component

export class InputTextComponent {
  @ViewChild(TemplateRef, { static: false }) template;
  constructor(private vcr: ViewContainerRef) {}

  ngAfterViewInit() {
   setTimeOut(()=> this.vcr.createEmbeddedView(this.template));
  }
}

Template

<ng-template>
  <label for="input01" class="col-2 col-form-label">First Name</label>
    <div class="col-4">
        <input type="text" class="form-control" id="input01" placeholder="First Name">
  </div>
</ng-template>

Stackblitz and original source of work around

Edit: As @Emilio Numazaki stated in the comments if you expose bindable properties it will cause mentioned exception to be thrown. So another workaround is needed to avoid that.

Sign up to request clarification or add additional context in comments.

3 Comments

Yes! This is exactly what I need! Thank you!
Heldar, there just one change I did in order to avoid ExpressionChangedAfterItHasBeenCheckedError error: Instead of direct call to this.vcr.createEmbeddedView(this.template), I did: Promise.resolve(null).then(() => this.vcr.createEmbeddedView(this.template));
It is important to avoid errors when you add more parameters to component. Please see the version with error: stackblitz.com/edit/angular-y2wnde

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.