Home > OS >  Angular - ViewChild vs document.querySelector
Angular - ViewChild vs document.querySelector

Time:05-02

I searching for the correct way of accessing DOM elements in Angular.

I am working on an example, which requires access to the DOM elements, because I want to change the offsetTop and the scrollTop properties of my HTMLElements.

I managed to implement my desired feature by querying the DOM elements using document.querySelector('.my-query-class') inside ngAfterViewInit(). The only issue is that I am querying a div-element, which has a certain CSS class. The div-element, which has this CSS class, changes. This means: There are multiple div-elements, and their CSS class is given by [ngClass] = {'.my-query-class': condition}. The condition changes upon clicking onto another div. So, I have to update the assignment myDOMElement = document.querySelector('.my-query-class') inside a click-listener. I hope this is more or less clear. In my typescript file I am basically doing the following:

myDOMelement?: HTMLElement;

ngAfterViewInit() {
    myDOMElement = document.querySelector('.my-query-class') as HTMLElement;
}

onClick() {
    myDOMElement = document.querySelector('.my-query-class') as HTMLElement;
    if (myDOMElement !== undefined) {
        doSomething();
    }
}

Now, even though this works fine, I have a feeling I am not suppossed to solve my problems using document.querySelector(). That's why I am looking for an alternative that Angular offers. I have stumbled across the ViewChild decorator and tried to implement my feature using it:

@ViewChild('.my-query-class') myDOMElementRef?: ElementRef;
myDOMElement?: HTMLElement;

ngAfterInitView() {
    myDOMElement = myDOMElementRef.nativeElement;
}

onClick() {
    if (myDOMElement !== undefined) {
        doSomething();
    }
}

It seems that myDOMElement is undefined though. Apparently I don't understand the correct way of using ViewChild. Can somebody explain?

CodePudding user response:

I'm not an angular expert but I have find out that this is a common problem.

View child seems that it works if you use an id.

I let you a code that it works :)

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

@Component({
  selector: 'app-question4',
  template: `
    <p #idElem >question4 works!</p>
    <button (click)="onButtonClick()">Button</button>
  `,
  styleUrls: ['./question4.component.sass']
})
export class Question4Component implements AfterViewInit {

  myDOMelement?: HTMLElement;

  constructor() { }

  // @ViewChild('.my-query-class') myDOMElementRef?: ElementRef;

  @ViewChild('idElem') myDOMElementRef?:ElementRef;
  ngAfterViewInit() {
    this.myDOMelement = document.querySelector('.my-query-class') as HTMLElement;
    console.log("this.myDOMElementRef");
    console.log(this.myDOMelement);
    console.log(this.myDOMElementRef);
  }

  onButtonClick(): void {
    console.log("button clicked!!");
    console.log(this.myDOMelement);
    console.log(this.myDOMElementRef);
  }
}

CodePudding user response:

If you are accessing an element in Angular using ViewChild, you have to give a template reference to that element.

<div #queryElem ></div>

In TS File

ViewChild('queryElem', {static: false}) divElem: ElementRef;

Also don't access element in ngOnInit hook. Always access DOMElement in ngAfterViewInit.

Refer this doc link to learn about hooks

  • Related