2016-10-25 4 views
15

В ngOnInit, мой компонент получает список пользователей, как так:Как принудительно обновить службу Observable в Angular2?

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 для вставки данных, но мне интересно, как это будет сделано в случае, если это невозможно по какой-либо причине.

ответ

11

Для того, чтобы наблюдаемый мог обеспечить значения после того, как начальный Http наблюдаемый был завершен, он может быть предоставлен субъектом RxJS. Поскольку поведение кеширования желательно, ReplaySubject подходит для случая.

Это должно быть что-то вроде

class UserService { 
    private usersSubject: Subject; 
    private usersRequest: Observable; 

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

Поскольку тема уже существует, то новый пользователь может быть сдвинут без обновления списка с сервера:

this.getUsers().take(1).subscribe(users => 
    this.usersSubject.next([...users, newUser]) 
) 
+0

Много больших ответов здесь. Я пошел с предложенным вами подходом, и он отлично работает. – Josh1billion

+0

Ницца, рад, что это работает для вас. – estus

+0

как отписаться от этого метода? –

3

То, как я справлялся с этой проблемой, заключается в использовании посредника. this.userService.getUsers() возвращает Rx.BehviorSubject, который инициализируется возвратом HTTP-наблюдаемого.

Что-то близко к этому:

getUsers() : BehaviorSubjec<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.onNext(value)}); 
} 
2

Возможно посмотреть в использовании реализации Redux, такие как ngrx/магазин, это делает управление состоянием между компонентами очень простым и predicatable. Просто отправьте нового пользователя в магазин, и это будет распространяться на все компоненты, имеющие ссылку на наблюдаемые магазины.

ngrx/store

Если вы размещаете больше вашего кода компонента я могу изменить это рабочий пример.