Best way to re-initialize your own NgModule providers?


#1

Hi, we have an interesting issue where we have a number of providers with spread use around the application where each also has some data stored (mostly an array of objects they handle). Now the problem we are facing is how do we “reset” these injectable services when the user logs out? We want to do a complete flush, preferably so that the next login attempt the modules are recreated since we also do some initialization in the constructors of them (starting sync of data to server).

At the moment the only way I can see us handling this manually is to inject all our services in the “homepage” that the user goes to after logging in. And then from there explicitly also call some destroy/reset method in our service when e.g. the homepage is unloaded. It also means we have to manually call some init method in each service as well after the user has logged in. Atm these were instantiated and initialized as needed when they were first injected (some services are actually not needed until you reach that particular page).

Would love to get some best practices and best ways to solve this from other coders here!


#2

Not sure I can claim it’s a “best practice”, but I have found life in Angular-land much more natural once I made an attempt to do things in a reactive manner (as opposed to imperative), and managing user authentication state is probably the poster child for this for me.

So you have an authentication state service (or bolt this functionality onto some other natural service that already exists).

authNotifier: ReplaySubject<boolean> = new ReplaySubject<boolean>(1);

You can replace boolean with some sort of credential object if that’s important to you. I have generally found that in most situations, all I care about is “authenticated or not?”. Login/logout is as simple as injecting this service and calling next(true) or next(false) on authNotifier. The reason for a stack depth of 1 is that we only want to know about the most recent authentication state, not history.

Now in your other providers, you can do this:

constructor(auth: AuthService) {
  auth.authNotifier.subscribe((authed) => {
    if (authed) {
      this.goGetStuff();
    } else {
      this.burnEverythingDown();
    }
}

…and in your app component, similarly:

constructor(auth: AuthService) {
  auth.authNotifier.subscribe((authed) => {
    if (authed) {
      this.rootPage = DashboardPage;
    } else {
      this.rootPage = LoginPage;
    }
}

Ionic 2, how to show alert and do navigation in Service
#3

I have realized working in react is quite different from what I am used to. But the issue I face is basically the same as that one encounters with any singletons. Who initializes the singleton (providers), when is it initialized, and who is responsible for taking it down/resetting it again so it doesn’t contain data from the previous user? I mean in standalone applications in general this isn’t a problem as you actually exit the whole application so everything is purged. But in a phone app, sign out doesn’t really mean its purged - the same providers linger with whatever they had when they were first instantiated on the fly by the first injection.

As of now I decided to inject all providers in the home page where you land after login and then actively call init on each of them so I can control when they are actually doing stuff (some even rely on each other) and are also then able to take each provider down in the order I want as the home page is unloaded from the nav stack. For now it seems to work well.


#4

I wish you luck, but this is precisely the sort of thing that I have vowed to avoid doing at all costs. It’s bringing an imperative screwdriver to try to hammer a reactive nail.


#5

Hehe, yes I see this is a different paradigm. But we do use callbacks and such between the providers. We just had issues where the constructor of each provider started a lot of things that was no longer done after a logout since the providers were not re-instantiated and re-injected, hence they passed in a state of the previous person logged in and we basically needed some way to clean their state out and the only way was to have one page that had all services injected call an explicit clean/reset method. It just felt right then to also take the opportunity to control more of when they were actually initialized too.

One possibility we thought of was instead of storing state in each provider, we could have some kind of common “storage” provider object instead, that all the others used, but since our provider objects also used generic typed collections we found that a bit more tricky. A common storage object would be easier to reset then on a logout as it meant injecting only that one object in the page that needs to clear it.


#6

I respect your decision, but since you did ask for opinions, mine is that that was not the only way. It’s one way that I have tried and eventually binned in favor of using Observables.


#7

And I am thankful for your reply. I certainly see that it is wise to use Observables. So am I right that you don’t have any state inside your providers then? You see our application has a requirement that it should work offline as well, which basically means we have to juggle between storing what the user does in the phones storage and then syncing that to the server whenever the user is online. We chose to deal with each “entity” of data in a generic way, that way we could manage simple generic lists of typed objects and the way they were handled were basically identical (with some options to control exactly what was passed down for each rest post).


#8

I guess that depends on how you define “state”. The authentication notifier is often tied to the storage provider which does hold things like authentication tokens and user preferences. The main difference is the inversion of control, which I think meshes nicely with Angular’s dependency injection. You mentioned earlier:

In a DI framework, I find it most natural to design the application so that I can happily answer “I don’t care” to any of that. I think in terms of events: user authenticates, user logs out, network connection exists, we are offline, user wants to refresh data, etc. Various services and components react to those things by subscribing to observables that notify them, and they each take care of doing whatever makes sense for them in response. This makes the entire class of “uh oh, page B forgot to call refrobulate on the cache” bugs completely go away, because it’s no longer anybody’s responsibility but the cache to maintain itself.

You might want to take a look at PouchDB; it sounds like you’ve reinvented it.