1
votes

I'm working on an angular app which has a parent and a list of children components. The parent uses two api calls:

  • A: returns a boolean that show/remove the children from the DOM.
  • B: show/remove a title in a div in the parent component.

I wanted to add a property to each child via ViewChildren decorator and ngAfterViewInit, so I put the following in it in the parent.

  @ViewChildren(ChildrenComponent) children: QueryList<ChildrenComponent>;


  ngAfterViewInit() {
    this.children.changes.subscribe((children) => {
       children.forEach((child) => {
           child = 'Property!!'; // this string is dynamic in my app.
       })
    });
  }

The subscription was triggered after API call A has returned. It's expected, since a new child is added to the QueryList. However, after API call B has returned, it also gets called.

Based on the documentation on ViewChildren decorator, it should only get called when a child is added, moved, removed from QueryList. However, API call B only touches a div outside of the children. Why did it triggers the subscription?

I have included a SandBox to illustrate this behavior: https://codesandbox.io/s/angular-fll6r

ViewChildren documentation: https://angular.io/api/core/ViewChildren

1
Did you find out what the problem was? - knoefel

1 Answers

0
votes

Your apiARes will be activated after 1 second. Within the period, there is no child loaded inside the parent. For demonstration purposes, you will get undefined when you check

 ngOnInit() {
    console.log(this.children) //undefined
    // API call A
}

Once the API is called, the child is loaded which is a change detection in the child. You will get Query result

setTimeout(() => {
      this.apiARes = true;
      console.log(this.children) // Query result
    }, 1000);

ngAfterViewInit() is called after the view of child is initially rendered. This is why @ViewChildren() depends on it. We can't access child members before they are rendered.