Как принудительно обновить службу Observable в Angular2?
В ngOnInit
мой компонент получает список таких пользователей:
this.userService.getUsers().subscribe(users => {
this.users = users;
});
И реализация userService.getUsers() выглядит так:
getUsers() : Observable<UserModel[]> {
return this.http.get('http://localhost:3000/api/user')
.map((res: Response) => <UserModel[]>res.json().result)
.catch((error: any) => Observable.throw(error.json().error || 'Internal error occurred'));
}
Теперь, в другом компоненте, у меня есть форма, которая может создать нового пользователя. Проблема в том, что, когда я использую этот второй компонент для создания пользователя, первый компонент не знает, что он должен сделать новый запрос GET для бэкэнд, чтобы обновить его представление о пользователях. Как я могу это сказать?
Я знаю, что в идеале я бы хотел пропустить этот дополнительный HTTP-запрос GET и просто добавить данные, которые уже есть у клиента, когда он заставлял POST вставлять данные, но мне интересно, как это сделать в случае, когда это невозможно по любой причине.
Ответы
Ответ 1
Чтобы наблюдаемая могла предоставить значения после того, как начальная Http наблюдаемая была завершена, она может быть предоставлена субъектом RxJS. Поскольку поведение кэширования желательно, ReplaySubject
подходит для этого случая.
Это должно быть что-то вроде
class UserService {
private usersSubject: Subject;
private usersRequest: Observable;
private usersSubscription: Subscription;
constructor(private http: Http) {
this.usersSubject = new ReplaySubject(1);
}
getUsers(refresh: boolean = false) {
if (refresh || !this.usersRequest) {
this.usersRequest = this.http.get(...).map(res => res.json().result);
this.usersRequest.subscribe(
result => this.usersSubject.next(result),
err => this.usersSubject.error(err)
);
}
return this.usersSubject.asObservable();
}
onDestroy() {
this.usersSubscription.unsubscribe();
}
}
Поскольку тема уже существует, нового пользователя можно отправить без обновления списка с сервера:
this.getUsers().take(1).subscribe(users =>
this.usersSubject.next([...users, newUser])
)
Ответ 2
До сих пор я решал эту проблему, используя посредника. this.userService.getUsers() возвращает Rx.BehviorSubject, который инициализируется при возврате наблюдаемой http.
Нечто близкое к этому:
getUsers() : BehaviorSubject<UserModel[]> {
return this.behaviorSubject;
}
updateUsers() {
this.http.get('http://localhost:3000/api/user')
.map((res: Response) => <UserModel[]>res.json().result)
.catch((error: any) => Observable.throw(error.json().error || 'Internal error occurred'))
.subscribe((value) => {
this.behaviorSubject.next(value)});
}
Ответ 3
Возможно, посмотрите на использование реализации Redux, например ngrx/store, это делает управление состоянием между компонентами очень простым и предикативным. Просто отправьте нового пользователя в хранилище, и это будет распространяться на все компоненты, имеющие ссылку на наблюдаемые магазины.
ngrx/store
Если вы разместите больше своего кода компонента, я могу отредактировать его в рабочем примере.