Angular2 APP_INITIALIZER not consistent

前端 未结 4 1896
名媛妹妹
名媛妹妹 2020-12-06 01:57

I am using APP_INITIALIZER like it is recommended in this answer, with my service returning a promise, but it doesn\'t always wait for it to resolve and I can see my compone

相关标签:
4条回答
  • 2020-12-06 02:03

    Guard your route with a CanActivate class using a Promise which loads the config settings should also work.

    Use the appSettings.service with a function just like the one returning a promise

    getAppSettings(): Promise<any> {
            var observable = this.http.get(this.ApiUrl, { headers: this.headers })
                .map((response: Response) => {
                    var res = response.json();
                    return res;
                });
    
            observable.subscribe(config => {
            this.config= config;
            console.log(this.config)
            });
            return observable.toPromise();  
        }
    

    And the CanActivate guard as below:

    import { Injectable } from '@angular/core';
    import { Router, CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
    import { AppSettingsService } from './appsettings.service';
    
    @Injectable()
    export class CanActivateViaAuthGuard implements CanActivate {
    
    //router: Router
        constructor(private appSettingsService: AppSettingsService)
        {
        }
    
        canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
                   return this.appSettingsService.getAppSettings().then(() => { 
        return true });
       }
    }
    

    This will ensure that your settings are available when the corresponding components are constructed. (using the APP_INITIALIZER did not restrict the constructor being called, so I had to use this technic, Also please make sure, you dont export all the components in the exports:[] in the module)

    To guard the routes and ensure settings are loaded before the constructors are called, please use the usual canActivate option in the path for the route definition

     path: 'abc',
     component: AbcComponent,
     canActivate: [CanActivateViaAuthGuard]
    

    The initialization of appsettings should happen before the constructor for AbcComponent is called, this is tested and works in Angular 2.0.1

    I'm not sure if it is the right place to load config but seems to serve the purpose

    0 讨论(0)
  • 2020-12-06 02:04

    Late, but if you want to keep your Service class returning Observables (I do), call it like this in your App Module class:

    function authenticationFactory(service: AuthenticationService) {
      console.log("calling login");
      //Call auth service login to get JWT info and startup data.
      //Also convert from an Observable to a Promise to work with APP_INITIALIZER.
      return () => service.login().toPromise().then(/*do nothing here*/);
    }
    
    NgModule Metadata stuff...
    
    providers: [
       ...
        AuthenticationService,
        {
          provide: APP_INITIALIZER,
          useFactory: authenticationFactory,
          deps: [AuthenticationService],
          multi: true
        },
        ...
      ],
    
    0 讨论(0)
  • 2020-12-06 02:21

    I think the problem is caused because you subscribe to the observable. This should work

    @Injectable()
    export class UserService {
    
        public user: User;
        constructor(private http: Http) { }
    
        getUser(): Promise<User> {
            console.log('get user called');
            return observable= this.http.get('/auth/getuser', { headers: getHeaders() })
                .map(extractData)
                .do(user => {
                    this.user = user;
                    console.log(this.user)
                 })
                .toPromise();
        }
    }
    

    I'm not sure if toPromise() is necessary. I'd expect it to work with Observable as well.

    0 讨论(0)
  • 2020-12-06 02:22

    Try the following code:

    getUser(): Promise<User> {
        console.log('get user called');
        var promise = this.http.get('/auth/getuser', {headers: getHeaders()})
            .map(extractData)
            .toPromise();
        promise.then(user => {
            this.user = user;
            console.log(this.user);
        });
        return promise;
    }
    

    I was facing the same problem, and using a promise instead of a observable did the trick for me.

    0 讨论(0)
提交回复
热议问题