Shyamal Parikh
Shyamal Parikh

Reputation: 3068

App_Initializer not working with UI-router

UI-Router triggers route change as defined in config section before App_Initializer function is executed. In the below example home state's resolveFn is triggered before App_Initialzer's resolves.

How to solve this?

app.module.ts

@NgModule({
  declarations: [
    AppComponent,
    routingComponents
  ],
  imports: [
    BrowserModule,
    UIRouterModule.forRoot(
      { states: appRoutes, 
        useHash: true ,
        config: uiRouterConfigFn
      }
    ),
  ],
  providers: [
    {
        provide: APP_INITIALIZER,
        useFactory: test,
        multi: true
    }
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

function test(): Function {
  return () => delay();
}

function delay(){
  var deferred = new Deferred<any>();
  console.log("Initialization started: " + new Date());
  setTimeout(() => {
    console.log("Initialization Done: " + new Date());
    deferred.resolve();
  }, 5000); // Wait 3s then resolve.
  return deferred.promise;
}

app.routes.ts

export const routingComponents = [
    HomeComponent
  ];


let home = {
    name: 'home',
    url: '/home',
    component: HomeComponent,
    resolve:[
      {
        token: 'te',
        resolveFn:($state: StateService) =>{
          var deferred = new Deferred<any>();
          console.log("testing Home Component");
          deferred.resolve();
          return deferred.promise;
        }
      }
    ]
  }

  export const appRoutes = [
    home
  ];

  export function uiRouterConfigFn(router: UIRouter, injector: Injector) { 
    // If no URL matches, go to the `hello` state by default
    router.urlService.rules.otherwise({ state: 'home' });
  }

Upvotes: 2

Views: 1433

Answers (1)

Kevin Boucher
Kevin Boucher

Reputation: 16675

For anyone else who needs to solve this problem, you can use UIRouterModule's deferIntercept() method to prevent routes from initializing before APP_INITIALIZER has resolved. (Per Christopher Thielen (@ UIRouter): https://github.com/ui-router/angular/issues/206)

I was able to solve this issue by setting deferIntercept to true in app.module:

@NgModule({
    imports: [
        /* Other modules ... */
        UIRouterModule.forRoot({
            states: [
                /* States (routes) ...*/
            ],
            config: uiRouterConfigFn,
            deferIntercept: true, // Allows APP_INITIALIZER to complete before routing
            useHash: true,
        }),
    ],
    declarations: [
        /* Component declarations ... */
    ],
    providers: [
        AppConfig, {
            provide: APP_INITIALIZER,
            useFactory: initResources,
            deps: [AppConfig, TranslationConfigModule, UIRouter],
            multi: true,
        },
    ],
    bootstrap: [AppComponent],
})

^ This part prevents the routes from initializing.

It is then necessary to call listen() and sync() to resume the router:

export function initResources(config: AppConfig, translate: TranslationConfigModule, uiRouter: UIRouter) {
    const router = uiRouter;

    return () => config.load(translate).then(() => {
        /*
            Recover from `deferIntercept: true` in UIRouterModule
            import below. (Allows Ng APP_INITIALIZER to finish before
            routing begins.)
        */
        router.urlRouter.listen();
        router.urlRouter.sync();
    });
}

Upvotes: 4

Related Questions