Home > Back-end >  Angular: Access elementRef inside an ng-template
Angular: Access elementRef inside an ng-template

Time:01-24

I got a component that renders different form-field components via ng-template. Now I want to access a function inside the last rendered component.

I tried accessing it with the ViewChildren() annotation with the string selector or the BaseClass all field-components (text-field, select-field) extend from.

allFields is always empty. Also tried accessing it as ContentChildren and the AfterContentInit lifecycle hook. Any Ideas how to achieve this?

It's much like this question, but it is still unanswered so I thought I'll ask it again. Thanks

HTML

<div *ngFor="let field of fields; fieldIndex as index">
  <ng-container *ngTemplateOutlet="getTemplate()"></ng-container>
</div>
<input type="button" (click)="doFunctionOnLastField()">

<ng-template #text>
 <text-field #field [field]=this.fields[fieldIndex]></text-field>
<ng-template>

<ng-template #select>
 <select-field #field [field]=this.fields[fieldIndex]></text-field>
<ng-template>

TypeScript

export class FormComponent implements OnInit, AfterViewInit {

 @Input() fields: FieldBase[];
 @ViewChild('text') text: TemplateRef<any>
 @ViewChild('select') select: TemplateRef<any>
 @ViewChildren('field') allFields;

 lastField: FieldBaseComponent;
 fieldIndex: number = 0;

 ngOnInit(): void {
  //...
 }

 ngAfterViewInit(): void {
  this.lastField = this.allFields.last; //this.allFields is empty
 }

 getTemplate() {
  // returns my template
 }

 doFunctionOnLastField() {
  this.lastField.someFunctionInsideTheField(); //this.lastField... is undefined
 }
}

CodePudding user response:

The rendered view and its children are only accessible when the template is rendered in the ViewContainerRef, so right here.

The rendered view cannot be obtained when usin ngTemplateOutlet, so i think your best bet is to copy the code and modify it to fit your requirements.

CodePudding user response:

The getTemplate() method would be called before ngAfterViewInit() is called.

When getTemplate() is called for the 1st time, it won't even return the TemplateRef, and it's only during next change detection cycle, the TemplateRef would be correctly returned and your fields would be rendered. Chances are that you may even get ExpressionChangedAfterItHasBeenCheckedError error.

So when ngAfterViewInit is called, your fields wouldn't have been rendered and hence this.allFields.last would be undefined.

Try to specify the static metadata property as true for the text and select ViewChild declarations:

@ViewChild('text', { static: true }) text: TemplateRef<any>;
@ViewChild('select', { static: true }) select: TemplateRef<any>;
  •  Tags:  
  • Related