webentwicklung-frage-antwort-db.com.de

Angular2 APP_INITIALIZER nicht konsistent

Ich benutze APP_INITIALIZER, wie es in this answer empfohlen wird, wobei mein Dienst ein Versprechen zurückgibt, aber er wartet nicht immer auf die Auflösung, und ich kann meine Komponente console.logging undefined sehen und dann den Dienst heruntergeladenes Objekt. 

Ich brauche die App, um nichts zu tun, bevor diese Daten geladen werden.

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

Versuchen Sie den folgenden 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;
}

Ich stand vor demselben Problem und es war für mich der Trick, ein Versprechen anstelle eines Beobachtbaren zu verwenden.

17
Remidy

Ich denke, das Problem liegt daran, dass Sie das Beobachtbare abonnieren. Das sollte funktionieren

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

Ich bin mir nicht sicher, ob toPromise() notwendig ist. Ich würde erwarten, dass es auch mit Observable funktioniert.

2

Schützen Sie Ihre Route mit einer CanActivate-Klasse mit einem Promise, mit dem die Konfigurationseinstellungen geladen werden sollten.

Verwenden Sie den appSettings.service mit einer Funktion wie die, die ein Versprechen zurückgibt

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

Und die CanActivate-Wache wie folgt:

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

Dadurch wird sichergestellt, dass Ihre Einstellungen verfügbar sind, wenn die entsprechenden Komponenten erstellt werden. (Mit APP_INITIALIZER wurde der aufgerufene Konstruktor nicht eingeschränkt. Daher musste ich diese Technik verwenden. Stellen Sie außerdem sicher, dass Sie nicht alle Komponenten in den Exporten exportieren: [] im Modul)

Um die Routen zu schützen und sicherzustellen, dass Einstellungen geladen werden, bevor die Konstruktoren aufgerufen werden, verwenden Sie bitte die übliche Option canActivate im Pfad für die Routendefinition

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

Die Initialisierung von appsettings sollte vor dem Aufruf des Konstruktors für AbcComponent erfolgen. Dies wird getestet und funktioniert in Angular 2.0.1 

Ich bin mir nicht sicher, ob es der richtige Ort ist, um config zu laden, scheint aber dem Zweck zu dienen 

1
abhijoseph

Spät, aber wenn Sie möchten, dass Ihre Service-Klasse Observables zurückgibt (ich tue), nennen Sie es in Ihrer App-Modul-Klasse so:

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