2016-09-27 61 views
10

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

我需要的应用程序在此数据加载之前不做任何事情。

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

它看起来OK。请说明您正在使用的软件包版本。你是否能够将问题复制为小提琴? – estus

+0

我不确定你为什么获取未定义值的日志,但是如果你在observable上同时使用'toPromise()'和'subscribe()',你将会调用'/ auth/getuser'两次。你应该链接rxjs运算符'share()'('rxjs/add/operator/share') –

回答

16

试试下面的代码:

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

我面临同样的问题,并使用一个承诺,而不是一个可观察的伎俩我。

+0

嘿,我确实在一段时间之前就开始工作了,但这正是我所做的。 – LLL

+0

我认为observables是在对象的第一次变化时触发的,它不包含所有的响应数据,而当整个任务完成时触发promise。投票了,因为这也解决了我的问题。 –

+0

@DesislavKamenov,不,它是“按设计”:)阅读此主题:https://github.com/angular/angular/issues/9047 – rook

1

卫队使用它加载的配置设置也应努力许诺一个CanActivate类路线。

使用appSettings.service与功能就像一个返回一个承诺

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

我不确定它是否适合l OAD配置,但似乎服务于此目的

2

我认为问题是由于您订阅观察。 这应该工作

@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一起使用。

0

晚,但如果你想保持你的服务类返回观测量(我),这样称呼它在你的应用程序模块类:

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