5

I want to use content projection, but I can't bring it to work.

The HTML is

<form [ngFormModel]="demoForm" (ngSubmit)="onSubmit()">
  <my-form-group myLabel="Some Label">
    <input type="text" [ngFormControl]="demoForm.controls['someInput'] [required]="true">
  </my-form-group>
</form>

The Component is

@Component({
  selector: 'my-form-group',
  template: `
    <div class="form-group">
      <label>{{myLabel}}<span *ngIf="required">&nbsp;*</span></label>
      <ng-content></ng-content>
    </div>
    `
})

export class MyFormGroup {
  @Input() myLabel: string;
}

How can I bind the *ngIf condition in the span to the required property of projected input element? The goal is to show the asterisk in the outer component, when [required] becomes true.

Edit: I made a - not working - plunkr to show what I mean.

2 Answers 2

3

You could reference the control within the ng-content using the ContentChild decorator:

@Component({
  selector: 'my-form-group',
  template: `
    <div class="form-group">
      <label>{{myLabel}}<span *ngIf="required">&nbsp;*</span></label>
      <ng-content></ng-content>
    </div>
  `
})
export class MyFormGroup {
  @ContentChild(NgFormControl) state; // <------
  @Input() myLabel: string;

  ngAfterViewInit() {
    this.required = (this.state.validator === Validators.required); // <-------
  }
}

This way you will have access to the control properties and specially the validator. If you have the Validators.required one, your input is required.

What is not clear to me is that you use ngFormControl and the required attribute. I think that you should use the following rather:

this.demoForm = formBuilder.group({
  someInput: ['', Validators.required ]
});

See this question for more details:

See also this article (section "Form component for fields") for more details:

Edit

After having dug a bit, you can check that the RequiredValidator directive is applied on the input:

@Component({
  selector: 'my-form-group',
  template: `
    <div class="form-group">
      <label>{{myLabel}}<span *ngIf="required">&nbsp;*</span></label>
      <ng-content></ng-content>
    </div>
  `
})
export class MyFormGroup {
  @ContentChild(RequiredValidator) requiredValidator; // <------
  @Input() myLabel: string;

  constructor(private cdr:ChangeDetectorRef) {

  }

  ngAfterViewInit() {
    this.required = (this.requiredValidator != null); // <-------
    this.cdr.detectChanges();
  }
}
4
  • Hallo Thierry, thank you for your quick answer. I want to allow change of attributes, like required or disable, controled by my outer component. If I would add Validators.required in my formbuilder.group, I would hardcode that, wouldn'd I? It seems to me, I can not use your compare with "this.state.validator", because there is no validator function available when I' using the attribute for that?
    – westor
    Commented May 2, 2016 at 9:21
  • You're welcome! So you want to use the inline declaration of validators with ngControl, not the use of FormBuilder? I ask because you use ngFormModel and ngFormControl... Commented May 2, 2016 at 9:32
  • I think I get it ;-) You can check if the RequiredValidator is applied on the input. I updated my answer accordingly ;-) Commented May 2, 2016 at 10:08
  • Unfortunatly I still cannot bring this to work. I made a plunkr to show what I mean. plnkr.co/edit/J3GaJHAjvBeTs3taTtvQ?p=preview - this.requiredValidatoris an empty object in my case.
    – westor
    Commented May 2, 2016 at 15:51
0

Because I got no more answers until now, in the meantime I tryed to find a solution. I found one, which is not really satisfying. I simple inject "required" also into the outer container. I don't like this solution, because a have inject the value twice.

And at the end I sticked with a new problem. But here is the code first:

<my-form-group myLabel="Hallo" [myRequired]="demoForm.controls['required'].value">
    <input type="text" [ngFormControl]="demoForm.controls['hallo']" [required]="demoForm.controls['required'].value">
    errors: {{demoForm.controls['hallo'].errors | json}}
</my-form-group>

And the component:

@Component({
  selector: 'my-form-group',
  template: `
  <div class="form-group">
    <label *ngIf="myLabel">{{myLabel}}<span *ngIf="myRequired">&nbsp;*</span></label>
    <ng-content></ng-content>
  </div>`
})
export class MyFormGroup {
  @Input() myLabel: string;
  @Input() myRequired: boolean;
  @ContentChild(NgFormControl) ctrl;
}

My next problem now is: Validation is not updated. Please see this Plunkr showing also the input's errors object. https://plnkr.co/edit/cBqSB6DX68EnqvnyqrGg?p=preview

Is there any solution for this? (or is it simply a bug?) And, if one has a better solution then mine, I would enjoy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.