Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ViewChildren not finding Dynamic Components

Tags:

angular

A parent component that contains a @ViewChildren is not returning results for components that are created dynamically.

The container component contains a highlight directive, and the dynamically generated component contains a highlight directive within it's template. When queried with @ViewChildren the query length returns 1. The expected result is 2.

As you can see from the HTML there are definitely two highlight directives on the DOM.

<container-component>
    <div></div>
     <dynamic-component ng-version="4.0.0">
        <div highlight="" style="background-color: yellow;">Dynamic!</div>
     </dynamic-component>
     <div highlight="" style="background-color: yellow;">Number of Highlights 
        <div></div>
     </div>
</container-component>

Am I missing something?

https://plnkr.co/edit/LilvHJgFjPHnPuaNIKir?p=preview

Container Component

@Component({
  selector: 'container-component',
  template: `
    <div #contentProjection></div>
    <div highlight>Number of Highlights {{highlightCount}}<div>
  `,
})
export class ContainerComponent implements OnInit, AfterViewInit {
  @ViewChildren(HighlightDirective) private highlights: QueryList<HighlightDirective>;
  @ViewChild('contentProjection', { read: ViewContainerRef }) private contentProjection: ViewContainerRef;

  constructor(
    private resolver: ComponentFactoryResolver
    ) {
  }

  ngOnInit() {
    this.createDynamicComponent();
  }

  ngAfterViewInit() {
    console.log(this.highlights.length);

    // Should update with any DOM changes
    this.highlights.changes.subscribe(x => {
      console.log(this.highlights.length);
    });
  }

  private createDynamicComponent(){
    const componentFactory = this.resolver.resolveComponentFactory(DynamicComponent);
    this.contentProjection.createComponent(componentFactory);

  }
}

Dynamic Component

 @Component({
      selector: 'dynamic-component',
      template: `
        <div highlight>Dynamic!</div>
      `,
    })
    export class DynamicComponent {
    }

Highlight Directive

 @Directive({
      selector: '[highlight]'
    })
    export class HighlightDirective {
      constructor(private elementRef: ElementRef) {
         elementRef.nativeElement.style.backgroundColor = 'yellow';
      }
    }
like image 635
cgatian Avatar asked Mar 29 '17 19:03

cgatian


People also ask

What is the difference between ViewChild and ViewChildren?

The ViewChild or ViewChildren decorators are used to Query and get the reference of the DOM element in the Component. ViewChild returns the first matching element and ViewChildren returns all the matching elements as a QueryList of items. We can use these references to manipulate element properties in the component.

How do you use ViewChildren?

We can use the @ViewChildren decorator to grab elements from the host view. The @ViewChildren decorator supports directive or component type as parameter, or the name of a template variable. When the parameter is a component/directive the return value will be the component/directive instance.

What is ViewContainerRef?

ViewContainerRef represents a container where one or more views can be attached. The first thing to mention here is that any DOM element can be used as a view container. What's interesting is that Angular doesn't insert views inside the element, but appends them after the element bound to ViewContainer .


1 Answers

That doesn't work because @ViewChildren only queries its own view, not the view contained within child components. Your dynamic component is a child component that has its own view.

To get around this you could add a @ViewChildren query in the dynamic component that has an output event to let anyone who cares (your parent component) know that a new instance exists.

like image 80
DRiFTy Avatar answered Sep 21 '22 07:09

DRiFTy