Search code examples
javascriptangulartypescriptngoninit

What is the best place to put a JavaScript listening function in Angular component?


TL;DR:

I am rendering a BioDigital HumanAPI anatomical model in my Angular 5 app within an iFrame. I instantiate API object using:

this.human = new HumanAPI(iFrameSrc);

There's an API function human.on(...) that can be used to register click events from within iFrame (like picking objects from the model, etc.). I need this function to be able to listen to the events at all times. I do the object instantiation and put this function within ngOnInit() and it works, but when I change the source of iFrame to render a different model, this function stops working. Where should I put this listening function so that its logic is available at all times?

Longer version:

I am developing an Angular app using BioDigital HumanAPI. The basic idea here is that HumanAPI provides several anatomical models which can be rendered in a web-app using an iFrame (an example here). The src of this iFrame is a link, something like:

https://human.biodigital.com/widget?m=congestive_heart_failure

Since I want the user of my Angular app to be able to view several of such models, I have a list of these URLs, and based on user's selection, I update the src of iFrame, using a function updateFrameSrc which has following code:

iframeSrc: SafeUrl;
this.iframeSrc = this.sanitizer.bypassSecurityTrustResourceUrl(newUrl);

Finally (the question is coming, please stay with me), in order to manipulate and register different click events and user interactions with the model within the iFrame itself, we make a HumanAPI object like this:

this.human = new HumanAPI(iFrameID);

This lets us use API event listener functions like human.on('scene.picked') to register and save click events (like shown in the example I referenced above). All of this is working fine.

The problem is that since I initialize the human object in the ngOnInit() function and also put the human.on('scene.picked') function there, I cannot register the click events after the iFrame source is changed. As I understand it, ngOnInit() is only called once when the component is first initialized, so may be the listening logic of human.on is not available after updating the iFrame source? I have tried placing the logic in different life-cycle hooks but its doesn't work.

My current work-around is to re-call the ngOnInit() function after updating the iFrame source, and it works that way, but I believe this is against the standard life-cycle management practices.

My questions are:

  • It is acceptable to re-call the ngOnInit() function from within the component logic?
  • If not, where should I place a JavaScript API function that listens to click events from an iFrame at all times, even after the source of that iFrame has been changed?

Solution

  • As suggested in an earlier comment, you can just move the code in ngOnInit() to a separate function and call that function from both ngOnInit() as well as your update function.

    Don't forget to re-initialize the human object of HumanAPI in that function as well, when updating the iFrame source.

    Re-calling ngOnInit() should be avoided as it circumvents the acceptable functionality of lifecycle hooks, as mentioned by @iHazCode.