Home > Mobile >  Make parent directives available to content rendered via ngTemplateOutlet in Angular
Make parent directives available to content rendered via ngTemplateOutlet in Angular

Time:09-19

Consider I have a form with multiple sections that are rendered using the ngTemplateOutlet.

<form [formGroup]="form">
    <ng-container *ngIf="true; then fooSection"></ng-container>
</form>

<ng-template #fooSection>
  <input type="checkbox" formControlName="isEulaAccepted">
<ng-template>

The problem is that formControlName can't access the parent formGroup directive.

Is it possible to make it work this way?

CodePudding user response:

You can't do that, I mean when you want to using formControlName, then you should have to put it inside [formGroup]="formGroup" section.

For an example, you only can do something like this code below:

<form [formGroup]="form">
  <ng-container *ngIf="true; then fooSection"></ng-container>

  <ng-template #fooSection>
  <input type="checkbox" formControlName="isEulaAccepted">
  <ng-template>
</form>

Update: Or you can do this, if you want to put outside [formGroup] section.

In your typescript, you can do add this:

public get isEulaAccepted(): FormControl {
  return this.formGroup.get('isEulaAccepted') as FormControl;
}

Or if you only have one formControl, so you should not have to using formGroup, just using formControl like this:

public isEulaAccepted: FormControl = new FormControl(null);

And, in your html, you can use this one:

<ng-container *ngIf="true; then fooSection"></ng-container>

<ng-template #fooSection>
  <input type="checkbox" [formControl]="isEulaAccepted" />
  <ng-template></ng-template
></ng-template>

Now, it will working fine.

CodePudding user response:

Note: FormControlName directive injects the ControlContainer with @Host() parameter decorator, so if it is not found in the parent, it throws an error. But you can provide the ControlContainer for it in another way.

  • create a wrapper component in the same file as the main component such this
let group;

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
  
})
export class AppComponent {
  name = 'Angular '   VERSION.major;

  @ViewChild(FormGroupDirective, { static: true }) formGroup: FormGroupDirective 

  form = new FormGroup({
    isEulaAccepted: new FormControl(),
  });

  ngOnInit() {
    group = this.formGroup;
  }
}

@Component({
  selector: 'wrapper',
  template: `<ng-content></ng-content>`,
  providers: [
    {
      provide: ControlContainer,
      useFactory: (app: WrapperComponent) => {
        return group;
      },
      deps: [forwardRef(() => WrapperComponent)],
    },
  ],
})
export class WrapperComponent {}

and use the WrapperComponent in template such this

<form [formGroup]="form">
  <ng-template
    *ngTemplateOutlet="fooSection;"
  ></ng-template>
</form>

<ng-template #fooSection>
  <wrapper>
    <input type="checkbox" formControlName="isEulaAccepted" />
  </wrapper>
</ng-template>

{{ formGroup.value | json }}

This is the final solution

  • Related