1

Currently when bootstrapping the app component angular2 doesn't wait for completion of all the lifecycle phases.

The following method start end sequence will be printed to the console:

AppComponent.ngOnInit() - START

SearchComponent.ngOnInit() - START

AppComponent.ngOnInit() - END

How can for the completion of all the lifecycle phases of app component be waited for, so that the sequence looks as follows:

AppComponent.ngOnInit() - START

AppComponent.ngOnInit() - END

SearchComponent.ngOnInit() - START

Andras Hatvani
  • 4,346
  • 4
  • 29
  • 45
  • 1
    What problem are you trying to solve? What code produces this output? – Günter Zöchbauer Oct 20 '16 at 07:53
  • I'm trying to initialize two services during application startup prior to the initialization of all components so that the components can use the cached results in ngOnInit or in the constructor. – Andras Hatvani Oct 20 '16 at 08:11
  • http://stackoverflow.com/questions/37611549/how-to-pass-parameters-rendered-from-backend-to-angular2-bootstrap-method/37611614#37611614. Perhaps also http://stackoverflow.com/questions/36271899/what-is-the-correct-way-to-share-the-result-of-an-angular-2-http-network-call-in – Günter Zöchbauer Oct 20 '16 at 08:12

1 Answers1

1

You can not control the lifecycle callbacks.

You can use

The chosen way for my problem was the usage of the APP_INITIALIZER. Services utilizing the router (such as Angulartics2) can't be used, because at this point the router hasn't been initialized yet. Below is an example code using async-await.

@NgModule({
imports: [
    HttpModule,
    routing,
    SharedModule.forRoot()
],
providers: [
    {provide: APP_BASE_HREF, useValue: '/'},
    {provide: APP_INITIALIZER,
        useFactory: (appModule:AppModule) => async () => {
            await appModule.init();
        }, deps: [AppModule], multi:true}
],
declarations: [AppComponent],
bootstrap: [AppComponent]
})
export class AppModule {

    constructor(private service:Service) {
    }

    // tslint:disable-next-line:typedef
    async init() {
        await this.service.init();
    }
}
Community
  • 1
  • 1
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • Are these approaches known to work with async-await, too? – Andras Hatvani Oct 20 '16 at 08:24
  • I don't know details about async-await in TS, but if it doesn't it's probably a bug in the async-await. – Günter Zöchbauer Oct 20 '16 at 08:25
  • I see. When I use the APP_INITIALIZER approach which seems to be best suited for me, then I see the following: Uncaught Error: Provider parse errors: Cannot instantiate cyclic dependency! ApplicationRef_: in NgModule AppModule – Andras Hatvani Oct 20 '16 at 08:30
  • You can work around that by injecting the `Injector` and getting the dependency by `this.myDep = injector.get(MyDependency);` instead of injecting `MyDependency` directly. – Günter Zöchbauer Oct 20 '16 at 08:31
  • Now I see the following error: zone.js:344Unhandled Promise rejection: Cannot read property 'componentTypes' of undefined ; Zone: ; Task: Promise.then ; Value: TypeError: Cannot read property 'componentTypes' of undefined(…) TypeError: Cannot read property 'componentTypes' of undefined – Andras Hatvani Oct 20 '16 at 08:40
  • Sorry, no idea. Can you reproduce in a Plunker? – Günter Zöchbauer Oct 20 '16 at 08:42
  • I think so, but maybe you've got an idea based on the fact that the error only occurs with custom services. – Andras Hatvani Oct 20 '16 at 09:17
  • AFAIR the error means that "something" is wrong in your code. Perhaps an import or similar. – Günter Zöchbauer Oct 20 '16 at 09:19
  • I've narrowed it down to: {provide: APP_INITIALIZER, useFactory: (injector:Injector) => { injector.get(Router); }, deps: [Injector]} // the router causes the exception even if it won't be injected/used in the service which I want to use. – Andras Hatvani Oct 20 '16 at 09:27
  • Hard to tell without a working repo case to investigate. – Günter Zöchbauer Oct 20 '16 at 09:31
  • I wasn't able to make the Plunker work but it's not related to `APP_INITIALIZER`. If I remove that whole provider I still get the same error. – Günter Zöchbauer Oct 20 '16 at 10:26
  • Try it now, please – Andras Hatvani Oct 20 '16 at 10:44
  • With the provided SampleService in the plunker it works in my environment, too. The main difference seem to be the dependencies which my LocationService has. – Andras Hatvani Oct 20 '16 at 11:29
  • Apparently all dependencies must be listed under "providers" despite all of them have been imported under "imports" in modules - this is both, redundant and error-prone. Is there a way to do it in a simpler way? I've just updated the plunker: If you remove "SecondSampleService" from the providers you have the failure. – Andras Hatvani Oct 20 '16 at 11:42
  • That shouldn't be necessary, except for lazy loaded modules which get their own root scope and their providers don't become available to the root scope of the non-lazy loaded modules. – Günter Zöchbauer Oct 20 '16 at 11:53
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/126231/discussion-between-andras-hatvani-and-gunter-zochbauer). – Andras Hatvani Oct 20 '16 at 12:29