Where to subscribe to events to avoid duplications

Hi, I’m using ionic 2 and I’m struggling a bit with where to subscribe to events in a page. I subscribe to an event with the following code

events.subscribe('preferences:updated', () => {
        //code
    });

at first I put this code into the page’s constructor, but the problem is that if I navigate out of the page and I come back to the page, the constructor code executes again. So if I receive an event, the code inside events.subscribe will execute as many times as the constructor was called.
Is there something I am missing?

thanks

Hello. Try subscribing in ionViewWillEnter and unsubscribing in ionViewWillLeave.

1 Like

thanks! yeah I found that, It looks like more than a hack than a proper solution, but it will help for the time being, thanks!

I created a rule for myself to lock out this error: I use subscribe in providers, but only use the async pipe in pages. That helps ensure that subscriptions are not duplicated.

How would you handle a situation where you have a multiproperty object referenced in several different places in the template? For example:

Dear {{person.honorific}} {{person.firstName}} {{person.lastName}}:

Your account number {{account.number}} at {{account.bank}} is currently overdrawn by {{account.balance}}.

If every property reference interpolation expression has its own async pipe instance, wouldn’t that result in triple the subscriptions and associated work as compared to handling the subscriptions in the controller and exposing person and account as objects?

I have two situations where that happens. I’m not sure I have a universal answer for you, but I’ll talk about those two.

  1. A list. Then the subscription looks like let item of items|async so item.name isn’t extra subscription overhead.
  2. A form or component where there’s a single object with many properties. In that case I define a ConnectableObservable in the controller, and multicast it to property Observables like this.honorific, this.firstName. So there’s one (potentially expensive) subscription to the provider, multicast to cheap Observable copies.
1 Like

If I’m understanding it accurately, #2 sounds like an awful lot of overhead (both per-property Observables and per-property AsyncPipes), not to mention added code complexity and what strikes me as overly tight coupling in that I prefer not to have templates know or care about the timing of updates to their property bindings.

This is probably partially an artifact of something we’ve discussed before, in that I write templates before controllers, so by the time I get around to populating the controller properties, the template has already “decreed” that the value is to be accessible in as simple a way as possible - which generally would be a simple POD object.

Tearing down subscriptions in lifecycle events doesn’t strike me as an overly onerous burden.

My context is that I’m inside Redux. Literally everything of interest is an Observable, so that’s a reasonable axiom for a template to know. Also, I forgot (3) which is actually more common than (2): separate out the component into its own file, pass the item as <componentName [input]="item|async"> and then use variables (not Observables) inside the component. So as a practical matter I might be doing what you’re doing more often than I’m doing (2).

But I should say that I’m ok with adding that level of complexity. If the page is a single form or component, extra overhead is not a big deal, and it’s worth it to me to avoid async runtime errors. To me, the cost of debugging async executions is worse than having too much code.

The point is to make sure to unsubscribe from events. You were seeing duplicates because you weren’t doing this. This is common with many pub/sub systems. I also recommend reading up on the framework lifecycle events (https://saniyusuf.com/ionic-by-component-page-lifecycle/) and try to avoid putting your subscriptions in the constructor where you can. Consider putting event methods in relevant providers and consolidating event topics, to avoid redundancy and typos.

2 Likes

One thing I think @AaronSterling and I do agree on is that Observables > Events.

1 Like

There is a hack but it working as intended , you may add like this in Constructor

            try
	{
		events.unsubscribe('<event identifier>');
	}
	catch(err)
	{
                 //use this if you need to know when this is called probably only once
	}
	events.subscribe('<event identifier>', () => {
		
	});

In case if any event already subscribed, it will be unsubscribe before subscribing new one.

Give a try