Search code examples
angularangular-directiveviewchild

Get children using viewChildren with nested directives


I am trying to implement some features in my angular application. I have created a parent directive appParent and two other directives appChildAbc and appChildXyz.

What I want to do is that whenever I have the appParent directive applied on an element, I want to check for its child elements (native HTML elements in the same component) and apply some logic to these child elements.

After much search and struggle I have found a way to do it using the ViewContainerRef in ParentDirective and @ViewChildren in AppComponent, but I had to use ((this.viewContainerRef as any)._view.nodes), which does not look like the right way to do it.

Is there any other way to get the reference of Child Elements in the parent directive ??

Sample stackblitz here

Feel free to fork the code and update as necessary. Thanks in advance

Parent Directive

export class ParentDirective {
  constructor(private vcr: ViewContainerRef) {}

  ngAfterViewInit() {
    console.log((this.vcr as any)._view.nodes);
    let lists = (this.vcr as any)._view.nodes.filter(
      x => x.constructor.name === "QueryList"
    );
    lists.forEach(list => {
      list.toArray().forEach(x => {
        if (x.constructor.name === "ChildXyzDirective")
          x.elementRef.nativeElement.style.background = "red";
        else x.elementRef.nativeElement.style.background = "green";
        console.log(x);
      });
    });
  }
}

App.component.ts

export class AppComponent  {
  name = 'Angular';
  @ViewChildren(ChildXyzDirective) xyzChildren: QueryList<ChildXyzDirective>;
  @ViewChildren(ChildAbcDirective) abcChildren: QueryList<ChildAbcDirective>;
}

App.component.html

<div appParent>
  Parent div directive
  <div appChildAbc>
    Abc Child directive 1
  </div>
  <div appChildAbc>
    Abc Child directive 2
  <div appChildXyz>
    Xyz Child directive 1
  </div>
  <div appChildXyz>
    Xyz Child directive 2
  </div>
</div>


Solution

  • you can use @ContentChildren decorator to query child directive

    ParentDirective

    @Directive({
      selector: "[appParent]"
    })
    export class ParentDirective {
    
     @ContentChildren(ChildXyzDirective,{descendants: true}) 
     xyzChildren : QueryList<ChildXyzDirective>;
    
     @ContentChildren(ChildAbcDirective,{descendants: true}) 
     abcChildren : QueryList<ChildAbcDirective>;
    
      ngAfterContentInit() {  
    
          this.abcChildren.forEach(e => {
            e.elementRef.nativeElement.style.background = "red";
          });
    
          this.xyzChildren.forEach(e => {
            console.log(e)
            e.elementRef.nativeElement.style.background = "green";
          });
    
      }
    }
    

    ContentChildren Use to get the QueryList of elements or directives from the content DOM. Any time a child element is added, removed, or moved, the query list will be updated, and the changes observable of the query list will emit a new value.

    demo 🚀