0

I have been reading the Dynamic component loading for Angular section, provided in the link below, Seeming highly complex and confusing my small brain, hard to understand all the syntax and names.

https://angular.io/guide/dynamic-component-loader

My question is what does @ViewChild do? the angular documentation states:

Property decorator that configures a view query.

But this doesn't give any understanding of what it does "what is a view query, what does that mean"? or why we are using it.

I later googled what is a view query which gave:

A view query is a requested reference to a child element within a component view which contains metadata of the element

But again I don't know really why or what this is doing for me in the code that follows that is shown in the above url.

Maybe this section should be after directives as I must be missing something.

when it calls this in the loadComponent() function, the adHost is a Directive that seems to be empty(no code in it) if you look at the below code, what is viewContainerRef, is ViewContainerRef my actual child component?

const viewContainerRef = this.adHost.viewContainerRef;
viewContainerRef.clear();

Does anyone know of any sites with simple and understandable uses for this?

The ad-banner.component.ts looks like this:

import { Component, OnInit, OnDestroy, Input, ViewChild, ComponentFactoryResolver} from '@angular/core';
import { AdItem } from '../ad-item';
import { AdDirective } from '../ad.directive';
import { AdComponent } from '../AdComponent';

@Component({
  selector: 'app-ad-banner',
  templateUrl: './ad-banner.component.html'
})
export class AdBannerComponent implements OnInit, OnDestroy {
  
  @Input() ads: AdItem[] = [];
  currentAdIndex = -1;

  @ViewChild(AdDirective, {static: true}) adHost!: AdDirective;
  interval: any;

  constructor(private componentFactoryResolver: ComponentFactoryResolver) { }

  ngOnInit(): void {
    this.loadComponent();
    this.getAds();
  }
  
  ngOnDestroy(): void {
    clearInterval(this.interval);
  }

  loadComponent() {
    this.currentAdIndex =(this.currentAdIndex + 1) % this.ads.length;
    const adItem = this.ads[this.currentAdIndex];

    const componentFactory = this.componentFactoryResolver.resolveComponentFactory(adItem.component);

    const viewContainerRef = this.adHost.viewContainerRef;
    viewContainerRef.clear();

    const componentRef = viewContainerRef.createComponent<AdComponent>(componentFactory);
    componentRef.instance.data = adItem.data;
  }

  getAds() {
    this.interval = setInterval(() => {
      this.loadComponent();
    }, 3000);
  }

}

The add-banner.comoponent.html looks like this:

<div class="add-banner-example">
    <h3>Advertisements</h3>
    <ng-template adHost></ng-template>
</div>

The ad.directive.ts looks like this:

import { Directive, ViewContainerRef } from "@angular/core";

@Directive({
    selector: '[adHost]'
})
export class AdDirective {
    constructor(public viewContainerRef: ViewContainerRef) {
        
    }
}
Andrew
  • 2,571
  • 2
  • 31
  • 56

1 Answers1

1

I believe that this post on the Angular University blog can help you out: https://blog.angular-university.io/angular-viewchild/. It's fully explained in a way that is easy to follow.

But, to anticipate, the ViewChild() is like a DOM Selector, but, with some interesting power. As you will learn in the post above, it can select the native DOM Element (for example, a simple DIV) or an instance of an Angular Feature like a component or directive, which gives you full access to its properties and methods.

That's what your code is doing: it is selecting the instance of the directive to where the ViewChild() is applied:

@ViewChild(AdDirective, {static: true}) adHost!: AdDirective;

In this case, you can inspect the adHost instance by implementing the ngAfterViewInit life cycle hook:

export class AdBannerComponent implements OnInit, OnDestroy, OnAfterViewInit {
  
  // .. all your code 
  
  ngAfterViewInit() {
    console.log(adHost);
  }
  
  // ... all your code (continued...)
}

By doing that you'll see how this can be powerful.

Dharman
  • 30,962
  • 25
  • 85
  • 135
Davi Silva
  • 30
  • 3
  • Thanks Ill take a read, should add to the knowledge. The example I was following missed lots of things out primarily the registration of the components and directives and entryComponents in the app.module.ts file. This link helped me get it working too https://stackoverflow.com/questions/48330760/cannot-read-property-viewcontainerref-of-undefined – Andrew Jul 21 '21 at 09:01