How to determine what observable been changed in Observable.merge?
Asked Answered
R

2

1

Below you can see my code that I have simplified for readability and clarity:

connect(): Observable<Customer[]> {
   const displayDataChanges = [
     this._customerDatabase.dataChange,
     this._filterChange,
     this._sort.mdSortChange,
     this._paginator.page
   ];
   return Observable.merge(...displayDataChanges).map(() => {
     let data = this._customerDatabase.data.slice();
     data = this.getFilteredData(data);
     data = this.getSortedData(data);
     const startIndex = this._paginator.pageIndex * this._paginator.pageSize;
     return data.splice(startIndex, this._paginator.pageSize);
   });
}

This method will return an Observable array of Customers.

The part below defines an array of Observables:

const displayDataChanges = [
      this._customerDatabase.dataChange,
      this._filterChange,
      this._sort.mdSortChange,
      this._paginator.page
];

Every time one of these emit data I expect my Array of Customers to change. (when i load the data, when my filter has changed, when i choose another sort mechanism and when i change the page)

I then Merge all of these together so that i can 'assemble' my data that has to be returned. As you can see, it is not very performant because it doesn't distinguish between what actual observable has emitted data...

How do I accomplish this and determine which observable has been changed? (Pseudo code below)

return Observable.merge(...displayDataChanges).map(() => {

 **[ALWAYS]**
 let data = this._customerDatabase.data.slice();

 **[IF MY SORTING HAS CHANGED]**
 data = this.getSortedData(data); /* After which i will change the dataSet */
 **[IF MY FILTER HAS CHANGED]**
 data = this.getFilteredData(data);

 **[ALWAYS]**
 const startIndex = this._paginator.pageIndex * this._paginator.pageSize;
 return data.splice(startIndex, this._paginator.pageSize);
});
Roaster answered 2/8, 2017 at 8:41 Comment(0)
D
3

One way you can do this is to make your Observables emit an object that has a type. For example:

connect(): Observable<Customer[]> {

   const typifier = (type) => {
       return (val) => {
           return { type: type, value: val };
       }
   };

   const displayDataChanges = [
       this._customerDatabase.dataChange,
       this._filterChange.pipe(map(typifier('filterChange'))),
       this._sort.mdSortChange.pipe(map(typifier('sortChange'))),
       this._paginator.page
   ];

   return merge(...displayDataChanges).pipe(map(obj => {

       let data = this._customerDatabase.data.slice();

       if (obj.type === 'filterChange')
       {
           data = this.getFilteredData(data);
       }

       if (obj.type === 'sortChange')
       {
           data = this.getSortedData(data);
       }

       const startIndex = this._paginator.pageIndex * this._paginator.pageSize;
       return data.splice(startIndex, this._paginator.pageSize);
   }));
}

Here is a link to a code snippet that you can play with that uses click and interval observables.

Dragonhead answered 1/5, 2020 at 18:34 Comment(0)
H
0

You could use combineLatest instead of merge. That way, you can grab an emitted value for each of your merged observables. All you have to do is to keep a reference of the last value of mdSortChange and _filterChange to check if they have changed.

CombineLatest documentation

connect(): Observable<Customer[]> {
  const displayDataChanges = [
    this._customerDatabase.dataChange,
    this._filterChange,
    this._sort.mdSortChange,
    this._paginator.page
  ];

  let lastFilter = null;
  let lastSort= null;

  return Observable
    .combineLatest(...displayDataChanges)
    .map(([newData, newFilter, newSort, newPage]) => {
      let data = this._customerDatabase.data.slice();

      if (newFilter !== lastFilter) {
        data = this.getFilteredData(data);
        lastFilter = newFilter ;
      }

      if (newSort !== lastSort) {
        data = this.getSortedData(data);
        lastSort = newSort;
      }

      const startIndex = this._paginator.pageIndex * this._paginator.pageSize;
      return data.splice(startIndex, this._paginator.pageSize);
 });
}
Hurry answered 2/8, 2017 at 9:5 Comment(4)
Hi Guillaume, thank you for answering! I have tried that but it doesn't seem to be executing the code inside the Observable?Roaster
With merge it does but then again, that was my problem ;)Roaster
Each displayDataChanges should emit at least one value. Can you ty changing page, filters and sorting to see if this is working ?Hurry
combineLatest only emits when all combined observables have emitted a least one value. Resulting observable emits an array containing the last emited value of each combined observables. merge emits whenever a merged observable emit. Resulting observable emit a single value (not an array).Hurry

© 2022 - 2024 — McMap. All rights reserved.