Search code examples
angularangular19

How to use useFactory with deps in the new provideAppInitializer?


I had the following code where I want the storage to init first, then the session, and then you shall enter the app.

export function initApp(
  storage: StorageService,
  session: SessionService,
) {
  return async () => {
    await firstValueFrom(
      storage.initialized$.pipe(
        filter((event) => (event ? true : false)),
        take(1),
      ),
    )

    await firstValueFrom(
      session.initialized$.pipe(
        filter((event) => (event ? true : false)),
        take(1),
      ),
    )
  }
}

I used to implement it like follow

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

But with the latest provideAppInitializer I cannot find the way to provide deps to my method.

It does seems the angular team have changed the way to use useFactory to implement it as follow :

provideAppInitializer(() => {
  const initializerFn = ((service: Service) => {
    return () => service.init();
  })(inject(Service));
  return initializerFn();
});

But I cannot wrap my head arround where to give my dependences.

Does somebody have any idea ?


Solution

  • Just inject it and use it.

    Make sure the init method returns a promise.

    provideAppInitializer(() => {
      const service: Service = inject(Service);
      return service.init();
    }); 
    

    If you want the initialization to happen sequentially, then use switchMap instead.

    provideAppInitializer(() => {
      const storage: StorageService = inject(StorageService);
      const session: SessionService = inject(SessionService);
      return firstValueFrom(
          storage.initialized$.pipe(
            filter((event) => (event ? true : false)),
            take(1),
            switchMap(() => {
              return session.initialized$.pipe(
                filter((event) => (event ? true : false)),
                take(1),
              )
            })
          ),
          
      );
    }); 
    

    You can simplify your code to:

    provideAppInitializer(() => {
      const storage: StorageService = inject(StorageService);
      const session: SessionService = inject(SessionService);
      return firstValueFrom(
        forkJoin([ 
          storage.initialized$.pipe(
            filter((event) => (event ? true : false)),
            take(1),
          ),
          session.initialized$.pipe(
            filter((event) => (event ? true : false)),
            take(1),
          ),
        ])
      );
    });