Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I force a refresh on an Observable service in Angular2?

Tags:

angular

rxjs

In ngOnInit, my component obtains a list of users like so:

this.userService.getUsers().subscribe(users => {     this.users = users; }); 

And the implementation of userService.getUsers() looks like this:

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

Now, in another component, I have a form that can create a new user. The problem is that when I use that second component to create a user, the first component doesn't know that it should make a new GET request to the backend to refresh its view of users. How can I tell it to do so?

I know that ideally I'd want to skip that extra HTTP GET request, and simply append the data the client already has from when it made the POST to insert the data, but I'm wondering how it'd be done in the case where that's not possible for whatever reason.

like image 611
Josh1billion Avatar asked Oct 25 '16 21:10

Josh1billion


People also ask

Can I subscribe to an observable in the service?

The only case where the service might subscribe is if a method is called with an Observable and the service method's job is to do something with the data that the Observable eventually emits.

Are observables lazy?

No, they aren't lazy, but they are asynchronous.

What is observable in angular service?

Observables provide support for passing messages between parts of your application. They are used frequently in Angular and are a technique for event handling, asynchronous programming, and handling multiple values.


2 Answers

In order for an observable to be able to provide values after initial Http observable was completed, it can be provided by RxJS subject. Since caching behaviour is desirable, ReplaySubject fits the case.

It should be something like

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

Since the subject already exists, a new user can be pushed without updating the list from server:

this.getUsers().take(1).subscribe(users =>    this.usersSubject.next([...users, newUser]) ) 
like image 183
Estus Flask Avatar answered Oct 07 '22 17:10

Estus Flask


The way I've handled this problem so far has been to use an intermediary. this.userService.getUsers() returns an Rx.BehviorSubject which is initialized on the return of the http observable.

Something close to this:

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)}); } 
like image 32
Joshua Avatar answered Oct 07 '22 19:10

Joshua