я пытаюсь переписать свое приложение angularJS на angular2 поэтому у меня есть сервис, который загружает метки i18n с разных конечных точек. и мне нужно знать, когда все данные будут готовы.
в моих компонентах angularJS я могу сделать так
vm.loading = true;
backend.ready.then(() => {
loading = false;
backend.getAlias('anyLabel')
})
поэтому при загрузке === false я скрываю загрузчик и могу получить псевдонимы Но я не могу понять, как это сделать с помощью сервисов angular2 и наблюдаемых объектов. Теперь у меня есть что-то вроде этого:
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, zip, of, Subject } from 'rxjs';
export interface Alias {
code: string;
value: string;
}
@Injectable({
providedIn: 'root'
})
export class BackendService {
private aliases: Alias[];
private aliasDeclaration: Alias[];
public ready: Observable<boolean>;
constructor(private http: HttpClient) {
this.aliases = [];
this.aliasDeclaration = [];
this.ready = new Observable<boolean>();
}
private getAliases(): Observable<Alias[]> {
return this.http.get<Alias[]>('/json/get-aliases?lang=ru');
}
private getDeclarations(): Observable<Alias[]> {
return this.http.get<Alias[]>('/themes/backend/aliases-declaration.json');
}
public init(): void {
zip(this.getAliases(), this.getDeclarations()).subscribe(([aliases, declarations]) => {
this.aliases = aliases;
this.aliasDeclaration = declarations;
// i need to set ready = true here, but can't figure out how :)
});
}
public getAlias(code): Alias {
return this.aliases.find(alias => alias.code === code);
}
public getAliasDeclaration(code): Alias {
return this.aliasDeclaration.find(alias => alias.code === code);
}
}
используйте behaviorSubject
public ready= new BehaviorSubject(false);
сделать готовым излучать
public init(): void {
zip(this.getAliases(), this.getDeclarations()).subscribe(([aliases, declarations]) => {
this.aliases = aliases;
this.aliasDeclaration = declarations;
// i need to set ready = true here, but can't figure out how :)
this.ready.next(true)
});
}
Вы также можете подумать о make private _ready = new BehaviorSubject(false); public ready = this._ready.asObservable();
- тогда вы будете уверены, что никто другой не сможет передать новое значение в _ready, но все смогут его прочитать.
Я не уверен, что вы хотите делать с «готовым», если вы просто хотите присвоить значение, которое вы можете использовать this.ready = Observable.of(true);
, и добавить импорт для Observable из import { Observable } from 'rxjs';
я просто пытаюсь убедиться (в своих компонентах), что все мои псевдонимы загружены, и компонент может использовать их, а также показывать/скрывать загрузчик и другие вещи.
Существуют различные варианты, но я бы вернул Observable из метода init
, хотя я предпочитаю добавлять суффикс Async
к своим методам, которые возвращают Observable или обещание.
import { shareReplay, map } from 'rxjs/operators';
public initAsync(): Observable<BackendService> {
const merged = zip(this.getAliases(), this.getDeclarations()).pipe(shareReplay());
merged.subscribe(([aliases, declarations]) => {
this.aliases = aliases;
this.aliasDeclaration = declarations;
// i need to set ready = true here, but can't figure out how :)
});
return merged.pipe(map(() => this));
}
shareReplay
гарантирует, что будет использоваться один и тот же результат. Я также возвращаю сам сервис из Observable, хотя в этом нет необходимости. Это позволяет подписчику легко использовать услугу, которая уже готова, но вернуть все, что вы хотите.
Телефонный код
ngOnInit() {
this.service.initAsync().subscribe(_ => /*do something*/);
}
Выглядит довольно легко, спасибо! Я думаю, мне нужно прочитать некоторую документацию