Angular2+ - how to dynamically select child component and call its function?

Viewed 245

I have a question about Angular2 + (not AngularJs). I'm a Vue.js programmer and I'm curious if it's possible in Angular.

Imagine that you have an application with many modules that perform many tasks. You have a frontend application responsible for monitoring module states; displaying logs, errors, informing the user that some modules have finished work, etc. The modules talk to the frontend via WebSocket (or STOMP). If the message is received by frontend, it must be processed and the corresponding state of the module must be updated (e.g. Title). So if Angular received the message, he must dynamically select the child component and update its state (call children method).

This is how it looks in Vue.js:

Content of the parent component:

<module ref="moduleA" ></module>
<module ref="moduleB" ></module>
<module ref="moduleC" ></module>

The parent is responsible for handling the WebSocket (or STOMP) communication. On the new message he executes the following code:

const message = JSON.parse(messageFromBackend);
const moduleName = message["module"]; // message["module"] is for example 'moduleB'
this.$refs[moduleName].updateTitle(message["title"]);

So, when Parent receive message, he dynamically select the appropriate child (he knows which one is right from the backend (message ["module"]) ), and then update module state.

Is it possible in Angular?

2 Answers

You can easily access child components from parent one. Just use ViewChild attribute. Child component class:

export class ChildComponent implements AfterViewInit {
    myAction();
}

In template of parent component:

<child-component #child1 ></child-component>
<child-component #child2 ></child-component>
<child-component #child3 ></child-component>

In parent component class:

export class AppComponent implements AfterViewInit {
    @ViewChild(ChildComponent) child1: ChildComponent;
    @ViewChild(ChildComponent) child2: ChildComponent;
    @ViewChild(ChildComponent) child3: ChildComponent;

    executeOnChildren() {
        this.child1.myAction();
        this.child2.myAction();
        this.child3.myAction();
    }
}

Or as according to your need you can use @ViewChildren attribute:

export class AppComponent implements AfterViewInit {
    @ViewChildren(ChildComponent) children: QueryList<ChildComponent>;

    executeOnChildren() {
        for(const child of this.children) {
            child.myAction();
        }
    }
}

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

To handle this parent-child communication I would create and Mediator Service with the possible events the parent can receive from the WebSocket connection and make each child subscribe to wherever events they need to know about. Like this you can easily handle scenarios like: children subscribing to multiple events.

This is the fragment where the parent emit the event

  emitEvent(){
    this.counter ++;
    let data: MyData = { name: '', somethingElse: this.counter }
    this.mediator.event1.emit(data);
  }

And here the child component subscribes to it

  ngOnInit() {
    this.mediator.event1.subscribe( (data: MyData) =>{
      this.label = data.somethingElse;
    });
  }

See the full example here: https://stackblitz.com/edit/angular-parent-child-mediator?file=src%2Fapp%2Fapp.component.ts

Related