Angular: How to access elementRef within an ng-template

I have a situation where I am using a component to render different form-field components through the use of ng-template. My goal is to access a function within the last rendered component.

I have attempted to access this function using ViewChildren() annotation with both the string selector and the BaseClass that all field-components (such as text-field and select-field) extend from.

However, the variable allFields always remains empty. I have also tried accessing it using ContentChildren and the AfterContentInit lifecycle hook. Does anyone have any suggestions on how to accomplish this?

This scenario is similar to a question posed in another forum post, but unfortunately that question remains unanswered. Therefore, I decided to inquire about it here. Thank you!

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: QueryList<ElementRef>;

 lastField: FieldBaseComponent;
 fieldIndex: number = 0;

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

 ngAfterViewInit(): void {
  this.lastField = this.allFields?.last?.nativeElement;
 }

 getTemplate() {
  // returns my template
 }

 doFunctionOnLastField() {
  this.lastField?.someFunctionInsideTheField();
 }
}

Answer №1

If you want to access the rendered view and its children, make sure the template is rendered in the ViewContainerRef. You can find more information about this here.

Unfortunately, the rendered view cannot be retrieved when using ngTemplateOutlet. In such cases, it's recommended to duplicate the code and customize it according to your specific needs.

Answer №2

Before the ngAfterViewInit(), the method getTemplate() will be invoked.

When getTemplate() is first called, it will not return the TemplateRef immediately; only during the next change detection cycle will the TemplateRef be returned correctly and your fields rendered. There is a possibility of encountering an ExpressionChangedAfterItHasBeenCheckedError error.

Therefore, when ngAfterViewInit is triggered, the fields will not have been rendered yet, causing this.allFields.last to be undefined.

Consider setting the metadata property static to true for the declarations of ViewChild for text and select:

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

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Is there a way to identify the accurate or incorrect array element and modify the component color accordingly?

Upon reviewing the question alternatives, I encountered a problem where clicking on one of the buttons correctly indicated whether it was the correct or incorrect answer by changing its color. However, the issue is that all buttons are being affected by th ...

Unlocking the power of React using TypeScript for optimal event typing

I need assistance with properly typing events in TypeScript. Consider the following function: import * as React from 'react'; someHandler = (event: React.SyntheticEvent<HTMLInputElement> | React.KeyboardEvent<HTMLInputElement>) =&g ...

What could be the reason for the form value object being devoid of any content

I am seeking help to understand how to write a custom validator for a reactive form. Here is the component code: private form: FormGroup; ngOnInit() { const this_ = this; this.form = new FormGroup({ 'email': new FormContr ...

update the data source of the material table inside the subscription

Seeking guidance for updating a MatTable datasource within an Angular application. The current Typescript code involves fetching data from an API using AdminService, iterating over the results to make additional API calls for more information about a fleet ...

Issue with Angular nested observable & forkJoin failing in one scenario, while it functions correctly in another

UPDATE The simulation for OtherService was incorrect. You can check the detailed explanation on this answer. I am trying to identify the issue in the test file that causes it to behave differently from the component. I am puzzled as to why the next: state ...

What is the method to obtain the complete URL in Angular?

I'm exploring ways to utilize Angular Universal in my app and I am seeking a method to retrieve the complete path of the current url within an Angular component. Initially, I considered tapping into the window object which would involve injecting it o ...

What is the best way to create a TypeScript function that can return either a string or an object?

I am working with a function that can return either a string or an object. Here is an example: myFunc(path: string): string | object If I already know the exact structure of the object that I am expecting, how can I ensure that the function returns a ty ...

Troubleshooting Typescript References

Currently, I have a web application that conducts basic analytics on user-imported data. Users can map columns and view property information on a map, as well as various statistics related to the properties. We are in the process of implementing a new fea ...

When using Vue 3 with Typescript, encountering the error message "No overload matches this call" can be frustrating even when the function name is clearly defined. It appears that the order of

While working with Vue 3 emit function and TypeScript, I encountered a strange error message. Here's an example code snippet to reproduce the issue: export default defineComponent({ emits: { emit1: (payload: number) => payload, emit2: (pa ...

The Angular2 Material Design framework combines sleek aesthetics with powerful

After setting up Angular2 Material Design, the libraries are located in the directory node_modules/angular2-material However, attempting to import any component from angular2-material results in the following error appearing on the browser: zone.js:101 ...

Strange activities observed during the management of state in react hooks, where the splice() function ends up eliminating the

My current setup involves maintaining a state to handle the addition of new JSX elements: const [display, setDisplay] = useState<IDisplay>({ BookingFormDropDown: [], } ); I have a function in onClick() which adds an elem ...

Adjusting the IntelliSense Functionality in Monaco Editor

Currently, I am testing out the CompletionItemProvider feature for my project. I have implemented two separate CompletionItemProviders. One is set to trigger when any alphabet letter is typed and the other triggers when the user enters a single quote chara ...

Implementing Angular 8 with Server-Side Rendering

After upgrading my app from Angular 5 to Angular 8 and enabling server side rendering, I encountered an issue. Despite starting the SSR server without any errors via terminal, I kept receiving the error below when running the application in the browser. I ...

No control access origin header found on the request to Spring 5 WebFlux functional endpoints

I have scoured numerous resources in search of the perfect solution to my issue. In my opinion, I believe I have all the necessary components in place but I am unable to pinpoint where the problem lies. Utilizing spring 5 with WebFlux and functional endpo ...

Ways to eliminate unnecessary items from a JavaScript object array and generate a fresh array

My JavaScript object array contains the following attributes: [ { active: true conditionText: "Really try not to die. We cannot afford to lose people" conditionType: "CONDITION" id: 12 identifier: "A1" ...

The Angular project failed to run properly following the ng build command

Just started working with Angularjs 2 and encountered an issue after running ng build. The compiled files were placed in the dist folder, but when I checked the index.html file within that folder, all the scripts had missing references even though they w ...

Get the base 64 file and convert it to an Excel spreadsheet

The encoded data in base 64 format is provided below. UEsDBBQAAAAIAIlimE8HQU1igQAAALEAAAAQAAAAZG9jUHJvcHMvYXBwLnhtbE2OPQsCMRBE/8px\nvbdBwUJiQNBSsLIPexsvkGRDskJ+vjnBj24ebxhG3wpnKuKpDi2GVI/jIpIPABUXirZOXaduHJdo\npWN5ADvnkc6Mz0hJYKvUHqgJpZnmTf4Ojka ...

Differentiating Views for a Single URL in Angular 6: Enhancing Progressive Web Apps

Below is the content from my app-router.module.ts import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { DheaderComponent } from './dheader/dheader. ...

Utilizing Angular Universal for Server-Side Rendering with dynamic absolute base href paths

Greetings! I have an application based on this particular starter kit. The app is deployed with the SSR feature from server.ts, and it is being served "dynamically" with Apache reverse proxy to localhost:4002 for multiple domains. For example, domainA.co ...

The Angular framework has identified an issue with the code on this particular line, pointing out an error

<if nameIsForbidden is true, then the span will display "This username is forbidden"></span> In the TypeScript file ngOnInit() { this.signupForm = new FormGroup({ 'userData': new FormGroup({ 'username': ...