0

I have this component:

<div #widget
     class="widget">
</div> 

@ViewChild('widget') widget!: any;

  ngOnInit() {
    console.log(this.widget.nativeElement) //returns undedined
  }

However it is working if I use native api:

console.log(document.querySelector('.widget'));

Then I've done some research and figure out that:

  @ViewChild('widget', {static: true}) widget!: any;

It is fixed the native element looking to the answers to this question, however the main answers there is quite confusing:

In most cases you will want to use {static: false}. Setting it like this will ensure query matches that are dependent on binding resolution (like structural directives *ngIf, etc...) will be found.

and

The { static: true } option was introduced to support creating embedded views on the fly. When you are creating a view dynamically and want to acces the TemplateRef, you won't be able to do so in ngAfterViewInit as it will cause a ExpressionHasChangedAfterChecked error. Setting the static flag to true will create your view in ngOnInit.

So now I do have a few questions

  1. Does it mean that @ViewChild('widget', {static: true}) widget! is equal to document.querySelector('.widget')?
  2. Is they are not equal in what cases I have to use @ViewChild('widget', {static: true}) widget! vs document.querySelector('.widget')?
  3. In what cases i should use @ViewChild('widget', {static: true}) widget! vs @ViewChild('widget', {static: false}) widget!?
  4. In my case I am not using any dynamic views but the refered answer suggesting to use {static: false} is quite bizarre.
Sergino
  • 10,128
  • 30
  • 98
  • 159

2 Answers2

1
  1. About {static:true} vs {static:false}.

    If your "div" is not under a *ngIf -it's always visible- you can indicate to Angular not "check" if exist or not each time else check only one time at very first stage of the component. For this you use {static:true}. In this way you can access so early as in ngOnInit

  2. About document.querySelector('.widget') vs @ViewChild

    Really a ViewChild you get a ElementRef (is in the property nativeElement where you get the "HTML element"). So with ViewChild you can access not only to the "HTML element", else, if is a component, to the component, if the tag has a directive to the directive.... Really you get a "reference" to any component or directive or HTML element.

    If you only has a simple tag (a div, a H1, a p, ...) the "Angular way" is also use ViewChild to insolate or encapsulate and not depend of if is executed in a navigator o not (really you get a reference to the DOM, some like <div ng_content-1 ....>), but as you can do the same with using reference.nativeElement and the document.querySelector really it's not much diference

Eliseo
  • 50,109
  • 4
  • 29
  • 67
  • so yeah in simple cases where you do not really need a power of framework you can just use querySelector, right? – Sergino Nov 10 '22 at 10:30
  • @sreginogemoh, yes. But really should be a few cases you need use it. e.g. if we want to add a class to a div, it's better use a variable `
    ` instead of ask about document.querySelector to add a class. (idem if you want to add an event). In general we should "think in variables" and "binding" properties better than manipulate the DOM directly.
    – Eliseo Nov 10 '22 at 14:13
0

You have can only access you widget after the view is initialized.

So, instead accessing it on ngOnInit() hook, you can access it on ngAfterViewInit().

export class AddUpdateFormComponent implements AfterViewInit {
  @ViewChild('widget') widget!: any;

  ngAfterViewInit() : void {
    console.log(this.widget.nativeElement)
  }

}
Khumo Mogorosi
  • 301
  • 2
  • 7