In my project, I have many components. And I have an event handler. When a particular event occurs, I want to call a particular method inside the component by it's name (if it exists in any of the component). Please find the below example:
@Component({
...
})
export class MyComponent {
public onMyEvent() {
// do stuff on that event
}
}
Here I want the onMyEvent()
to be called whenever an event occurs as below:
export class MyEventHandler {
private myEvent: Subject;
public registerEvents() {
this.myEvent.subcribe(() => {
// call "onMyEvent" function of all components that exists in the view
});
}
}
The scenario is similar to how ngOnInit()
, ngAfterViewInit()
.. works. When you implement OnInit
, AfterViewInit
interfaces, you are defining a contract that the component is guaranteed to have the specified method that is ready to be called at those times.
I want to do the same way.
This can be kind of achieved using ComponentRef
. But only a parant component can call it's child component and is very much dependent on the HTML structure. I want it to be as seamless as ngOnInit
.
I feel there are a few concepts running in parallel here, so forgive me if my answer is off-base. Please let me know which elements are incorrect and I can amend my answer accordingly
As I understand you want the following:
onMyEvent
tl:dr to achieve an
ngOnInit
like experience (something which works out of the box with no component configuration) all components would be forced to have a subscription setup by default, which is not great architecturally. A singleton service injected with subscription determined by the components themselves appears to be a much more sensible approach, but this requires setup that you don't have with lifecycle hooks and as such may not qualify as "seamless"Point 1 is simple enough, as you have already alluded to we can define a shared interface for a number of components to implement which mandates the presence of
onMyEvent
.Point 2 requires a single stream (i.e.
Observable
,Subject
,EventEmitter
, etc) which is capable of being watched by multiple componentsThe obvious solution for this would be a service which houses this stream and can be dependency injected into any component which requires it.
However, I am assuming that you do not want to generate a unique service instance for each component which requires it, you instead want a singleton service which broadcasts the same event to all components. As a result, you place the responsibility of subscribing to the event with the components themselves, i.e.
This requires a manual setup that you don't have with inbuilt lifecycle hooks like
ngOnInit
, but the difference here is that all components requirengOnInit
whereas only some of these components require a subscription tomyEventSubject
. It is this selectivity which prevents the experience from being as "seamless"You could of course explore a base class to keep your working components slightly more "neat"
But there seems little benefit over the previous implementation, considering you are still dependent on a service and selective subscription to the service variable (in this case selective extension of the
BaseEventHandler
)You also mention
ComponentRef
, i.e. presumably usingViewChild
to access a component instance and call the method in question in a fashion such as:However in this case, the watcher for the event would still have to reside in individual components (in this case the parent component instead of the child component) and as not all parent components would need to subscribe to the watcher, you once again would achieve this using selective subscription vs an always-available hook such as
ngOnInit()