angularviewchild

Div id is null when using ngAfterViewInit


In my application I am using angular, and I am trying to access a div right after the page loads. I have imported Afterviewinit like so:

import { Component, OnInit, ViewChild, AfterViewInit, ElementRef } from '@angular/core';

created a variable:

  @ViewChild('editPreamblesInput') editPreamblesInput: ElementRef;

and then implemented ngAfterViewInit like so:

  ngAfterViewInit(){
    const result = this.editPreamblesInput.nativeElement;
    console.log(result);
  }

my html is like:

  <div id="editPreamblesInput" #editPreamblesInput (mouseenter)="userEditable && isUrl? displayPreamblesLink.show() : null" (mouseleave)="displayPreamblesLink.hide()">
    <input-validation>
      <igx-input-group>
        <input igxInput name="preamblesRef" id="preamblesRef" type="text" formControlName="preamblesRef" [readonly]="!userEditable"
        inputValidationDirective [control]="libraryForm.controls['preamblesRef']"/>
        <label igxLabel for="preamblesRef">Preambles Reference</label>
      </igx-input-group>
    </input-validation>

  <igx-action-strip #displayPreamblesLink [displayDensity]="displayDensity" class="action-strip" [hidden]="true">
      <igx-buttongroup [multiSelection]="true" class="buttons">
          <button igxButton type="button" (click)="editPreamblesRef()">
              <igx-icon>link</igx-icon>
          </button>
      </igx-buttongroup>
  </igx-action-strip>
  </div>

However, when I look at my console I get the error: ERROR TypeError: Cannot read properties of undefined (reading 'nativeElement') at LibrarySetupComponent.ng

and editPreamnlesInput is null.

I'm not sure why this is null and what I am missing?

Edit:

So I've figured out why this is happening. The div is a part of a form which only shows if a boolean called loaded is set to true:

this gets set to true in a method called getData():

  getData() {
    this.libraryService.getAll().subscribe({
      next: (libraries) => {
        this.libraryList = libraries;

        if(this.route.snapshot.params['libraryId']) {
          const library = this.libraryList.find(l => l.id == this.route.snapshot.params['libraryId']);
          this.patchLibrary(library);
        } else {
          this.patchLibrary(this.getNewLibrary());
        }
        this.loaded = true;
      },
      error: (err) => {
        this.alertService.error(`Error getting ${this.alertVariable} data - ${err.message}`);
      }
    });
  }

this is then called in the ngOnInit method. loaded has a default value of false, if I change this to true I can then access that element. So I thought I could do something like:

  complete:() => {
    const test = document.getElementById("editPreamblesInput");
    console.log(test);

however test comes up as null. So I'm thinking I need to find a way so that I tell it to wait until the boolean is true before it tries to access it but not sure how


Solution

  • You need to use a template variable to access it.

    Inside your template:

    <div #div>Hello, world!</div>
    

    Inside your component:

    @Component({ ...})
    export class MyComponent implements AfterViewInit {
      @ViewChild('div') div?: ElementRef;
    
      ngAfterViewInit(): void {
        if (this.div) {
          console.log(this.div);
        }
      }
    }
    

    Here's a StackBlitz to see it in action:

    https://stackblitz.com/edit/angular-l1qyro?file=src%2Fmain.ts