web-dev-qa-db-ja.com

Angular2APP_INITIALIZERに一貫性がありません

this answerで推奨されているようにAPP_INITIALIZERを使用しており、サービスはpromiseを返しますが、それが解決するのを常に待つわけではなく、コンポーネントconsole.loggingが未定義であることがわかります。ダウンロードしたオブジェクトをログに記録するサービス。

このデータが読み込まれる前にアプリが何もしないようにする必要があります。

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

次のコードを試してください。

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

私は同じ問題に直面していました、そして観察可能なものの代わりに約束を使うことは私のためにトリックをしました。

17
Remidy

構成設定をロードするPromiseを使用して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を使用しても、呼び出されるコンストラクターが制限されなかったため、この手法を使用する必要がありました。また、モジュール内のexports:[]のすべてのコンポーネントをエクスポートしないようにしてください)

ルートを保護し、コンストラクターが呼び出される前に設定がロードされるようにするには、ルート定義のパスで通常のcanActivateオプションを使用してください。

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

Appsettingsの初期化は、AbcComponentのコンストラクターが呼び出される前に行う必要があります。これはテストされ、Angular 2.0.1で機能します。

設定をロードするのに適切な場所かどうかはわかりませんが、目的を果たしているようです

2
abhijoseph

オブザーバブルを購読しているために問題が発生していると思います。これはうまくいくはずです

_@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

遅くなりますが、ServiceクラスがObservablesを返すようにしたい場合は(私はそうします)、AppModuleクラスで次のように呼び出します。

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
Chris Moore