Angular2 APP_INITIALIZER不一致

时间:2016-09-27 13:18:03

标签: angular promise observable

我正在使用APP_INITIALIZER,就像this回答一样,我的服务返回一个承诺,但它并不总是等待它解决,我可以看到我的组件console.logging undefined然后服务记录下载的对象。

我需要应用程序在加载此数据之前不执行任何操作。

app.module.ts

import { NgModule, APP_INITIALIZER } from '@angular/core';
import { Http, HttpModule, JsonpModule } from '@angular/http';
import { UserService } from '../services/user.service';

<...>
@NgModule({
  imports: [
    BrowserModule,
    HttpModule,
    FormsModule,
    JsonpModule,
    routing
  ],
  declarations: [
    AppComponent,
    <...>
  ],
  providers: [
    <...>
    UserService,
    {provide: APP_INITIALIZER,
      useFactory: (userServ: UserService) => () => userServ.getUser(),
      deps: [UserService, Http],
      multi: true
    }
  ],
  bootstrap: [AppComponent]

user.service.ts

@Injectable()
export class UserService {

    public user: User;
    constructor(private http: Http) { }

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

        observable.subscribe(user => {this.user = user;
            console.log(this.user)});
        return observable.toPromise();
    }
}

4 个答案:

答案 0 :(得分:17)

请尝试以下代码:

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;
}

我遇到了同样的问题,使用诺言而不是观察对我来说是个窍门。

答案 1 :(得分:2)

我认为问题是由于您订阅了observable而引起的。 这应该工作

@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();
    }
}

我不确定toPromise()是否必要。我希望它也适用于Observable

答案 2 :(得分:1)

使用Promise保护您的路线,使用Promise加载配置设置也应该有效。

将appSettings.service与返回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();  
    }

CanActivate后卫如下:

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 });
   }
}

这将确保在构造相应组件时您的设置可用。 (使用APP_INITIALIZER并没有限制被调用的构造函数,所以我不得不使用这个技术,另外请确保,你不要导出导出中的所有组件:模块中的[])

为了保护路由并确保在调用构造函数之前加载设置,请使用路径定义路径中常用的canActivate选项

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

appsettings的初始化应该在调用AbcComponent的构造函数之前发生,这是在Angular 2.0.1中测试并运行的

我不确定它是否是加载配置的正确位置,但似乎是为了达到目的

答案 3 :(得分:0)

迟到了,但如果你想让你的Service类返回Observables(我这样做),请在你的App Module类中这样调用它:

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
    },
    ...
  ],