Angular2 APP_INITIALIZER несовместим
Я использую APP_INITIALIZER, как это рекомендуется в этом, с моей службой, возвращающей обещание, но она не всегда ждет, пока она разрешится, и я могу см. мой компонент 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();
}
}
Ответы
Ответ 1
Попробуйте использовать следующий код:
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;
}
Я столкнулся с той же проблемой, и использование обещания вместо наблюдаемого помогло.
Ответ 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
.
Ответ 3
Защитите свой маршрут с помощью класса CanActivate, используя Promise, который загружает настройки конфигурации, также должен работать.
Используйте приложение 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
Я не уверен, что это подходящее место для загрузки конфигурации, но, похоже, служит цели
Ответ 4
Поздно, но если вы хотите, чтобы ваш класс обслуживания возвращал 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
},
...
],