App initialization

Hi,

I have a generic question regarding initializing my app.
I see ppl using the app.component constructor to call a method like:

initializeApp() {
this.platform.ready().then(() => {
// do some stuff
}
}

Furthermore I saw projects using app.modules provider to declare:

{
provide: APP_INITIALIZER,
useFactory: initApp,
multi: true,
deps: [UserController]
},

and have the method also in app.module like:

export function initApp(controller: UserController) {
return () => {
return new Promise((resolve) => {
controller.loadUser();
resolve();
});
};
}

Could you please elaborate what are the main difference, and when to use which way? Or are there any other ways to initialize my app?
Standard use case I would like to do: load the user object from the local storage.

Any help appreciated
thanks a lot!

I’m afraid to answer your question directly, because I think it implies an imperative mindset that will cause you considerable pain going forward. I found myself much happier once I acknowledged that in web apps, I am not in control of the overall flow of execution.

This is an important pattern when you’re dealing with native functionality like Cordova plugins, as you cannot interact with them until the platform is ready. The other two code snippets don’t strike me as particularly fruitful.

Now, back to what I think you’re really confused about, which is:

How do I make sure that data is available when I need it?

I believe strongly in the importance of the principle of separation of concerns, and in Angular apps, that means that data is managed by services, as opposed to components. So you want a UserService that is shaped something like this:

interface User {...}
class UserService {
  watch(): Observable<User | undefined> {...}
  peek(): User | undefined {...}
  poke(u: User | undefined): void {...}
}

Now you’re free to try many different strategies for when and where to actually load this information, and nobody outside of UserService need know or care. You could do this:

class UserService {
  private user$ = new BehaviorSubject<User | undefined>(undefined);
  constructor(private storage: Storage) {
    this.storage.ready()
      .then(() => this.storage.get("user"))
      .then(user => this.user$.next(user));
  }
  watch(): Observable<User | undefined> {
    return this.user$;
  }
  peek(): User | undefined {
    return this.user$.value;
  }
  poke(u: User | undefined): void {
    this.user$.next(u);
    this.storage.set("user", u);
  }
}
2 Likes

Thank your very much for your reply! Highly appreciated.

_
I fully agree with the concept of having a Service that creates observables/promises and the compenents watch it, until they can use it.
But when talking about initialization, I thought that this might be a different scenario, no?

_
I try to give an example of what I mean. I want to login (or verify the locally stored validity of a user-token) when the app was opened. Using your suggested approach it would lead to:

App opened -> Splashscreen -> Login component -> App-startpage

Whereas the login component, subscribes on the UserService. That would lead to have two waiting screens (Splashscreen and LoginComponent) for the user.
Maybe this is the point where my confusion comes from, I believed that the whole login process can be done during the Splascreen is shown.

_
Thanks in advance for any other advise!

Let’s just concentrate on this, because it’s easy to answer. The splash screen displays while the app really is being initialized, at the lowest level. Until that first process gets done, none of your app code can execute, period, because it hasn’t been loaded yet.

The earliest sane place you can do anything involving locally stored data is in the constructor of a service.

1 Like