Search code examples
javascriptangulartypescriptrxjscombinelatest

Refreshing list using combineLatest: Angular2 + RxJS


I have a component in which I am displaying a table of data (users) generated from an http request to an API. There are a variety of filters on the table so I generate the table data as follows:

this.displayUsers$ = Observable.combineLatest(
            this.users$,
            this.siteFilter$,
            this.clientFilter$,
            this.activeFilter$,
            this.nameFilter$
        )
            .map(([users, siteFilter, clientFilter, activeFilter, nameFilter]) => {
                console.log("Users changed? ", users);
                if (siteFilter === null
                    && clientFilter === null
                    && activeFilter === null
                    && nameFilter.length < 1) {
                    return users;
                }
                return users
                    .filter(user => {
                        // manipulate users array based on filters
                    })
            });

The xFilter$s are BehaviorSubjects that emit new values in response to changes to their inputs in the template. users$ is assigned as follows:

this.users$ = this.userService.getList();

Where getList() returns an http request to get a list of users.

The list successfully updates whenever the filters are changed, but I have issues when I need to update the list with fresh users. For example, a user can perform CRUD operations on the table of users (ie delete a user). When the user is deleted, however, the table does not update to reflect this change. The method I am currently using to (try) to fresh the table is by calling a refresh function in the success callback of the delete operation:

refreshUserList() {
        console.log("Refreshing user list");
        this.users$ = this.userService.getList();
    }

Despite calling this after the operation is complete, the combineLatest observable does not get 'triggered' again and the list data remains stale. Is there a better way to refresh data generated by combineLatest with http requests?


Solution

  • The main problem is that in the case of user list update your users$ observable does not emit any new value. You have to make it do so.

    This is skeleton of an idea how to fix it:

    const updateUsersTrigger = new Subject<void>();
    
    this.displayUsers$ = Observable.combineLatest(
        // switchMap() will re-subscribe to this.userService.getList() observable on each emit from updateUsersTrigger
        // thus making http requests each time when user list should be updated.
        updateUsersTrigger.startWith(null).switchMap(() => this.userService.getList()),
        this.siteFilter$,
        this.clientFilter$,
        this.activeFilter$,
        this.nameFilter$
    )
        .map(([users, siteFilter, clientFilter, activeFilter, nameFilter]) => {
    
        .......
    
    });
    
    // this will trigger user list update
    updateUsersTrigger.next();