Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Subscribe to changes in parent component in Angular

Tags:

angular

I've a parent component which hosts a list of child components. This children are create dynamically and can be of any type.

So, what I'm doing is using an ng-container as host in the parent component, create the child components with ComponentFactoryResolver and then update some properties in the child component using ```(component.instance as any).id = host.id;````

Here is the code for parent component (it's a table with some rows):

<tr class="table-collapse__item" [class.active]="company === selected">
  <td [attr.colspan]="getItemColspan()">
    <ng-container host [id]="name" [selected]="isSelected"></ng-container>
  </td>
</tr>

host is a directive

@Directive({
  selector: '[host]'
})
export class Host implements OnChanges {
  @Input() id: any;
  @Input() selected: boolean;
  constructor(public viewRef: ViewContainerRef) {}
}

and finally how to create the components and update the properties

@ViewChildren(Host) hosts: QueryList<Host>;

  constructor(private resolver: ComponentFactoryResolver,
              private cd: ChangeDetectorRef) {}

  ngAfterViewInit() {
    if (this.hosts) {
      const componentFactory = this.resolver.resolveComponentFactory(this.inner);
      this.hosts.forEach((host: Host) => {
        const component = host.viewRef.createComponent(componentFactory);
        (component.instance as any).id = host.id;
        (component.instance as any).selected = host.selected;
      });
      this.cd.detectChanges();
    }
  }

Now, my question. I need the child component to react to changes in its properties, but as its properies are not Inputs but just basic properties, I can´t use ngOnChanges inside the childComponent. So it's there a way I can subscribe from the child component to changes in the parent component?

I can use ngOnChanges in the Host directive and update the properties in the component, but how to then trigger some code in the child component?

I have a plunker to test it. When clicking on data1, data2, data3 or data4, the row below should collapse or expande.

Thanks.

like image 462
David Avatar asked May 15 '17 08:05

David


People also ask

How does @input work in Angular?

Use the @Input() decorator in a child component or directive to let Angular know that a property in that component can receive its value from its parent component. It helps to remember that the data flow is from the perspective of the child component.

How do you pass value from child to parent component?

To pass data from child to parent component in React:Pass a function as a prop to the Child component. Call the function in the Child component and pass the data as arguments. Access the data in the function in the Parent .

How do you access the child component property in the parent component?

We can get child component values in the parent component by creating a reference to the child component using the @ref directive in the Parent component. Using the reference instance, you can access the child component values in the parent.


1 Answers

Child components can't listen to changes in the parent, but you can notify them about changes by calling a method on the children instead:

components =  [];
ngAfterVeiwInit() {
if (this.hosts) {
    const componentFactory = this.resolver.resolveComponentFactory(this.inner);
    this.hosts.forEach((host: Host) => {
      const component = host.viewRef.createComponent(componentFactory);
      (component.instance as any).id = host.id;
      (component.instance as any).selected = host.selected;
      this.components.push.components();
    });
    this.cd.detectChanges();
  }      
}

ngOnChanges() {
  this.components.forEach((c) => {
    c.instance.ngOnChanges(); // or any other method the child comonents have
  })
}
like image 155
Günter Zöchbauer Avatar answered Sep 21 '22 12:09

Günter Zöchbauer