Angularfire2 rxjs join observables from two tables with dynamic updates

So, I have two tables. One of them is my user who stores blocks. Another one stores data for these blocks.

I am trying to combine them correctly, so in my component I am getting a list of blocks with their data according to dataID

- user
    - blocks
        - block1
            - blockSize
            - blockOptions
                - dataID
        - ...

- data
  - dataId1
      - stuff ...
  - ...

      

With the following code, I am getting my blocks and data, but the node data is still FirebaseObervable. So I have to use async in my dumb components. I am asking how to combine them correctly, so I only need to use an async pipe and drag and drop data into subcomponents. Without losing dynamic changes.

return this.db.list(`/user/${this.userId}/blocks`).switchMap((blocks:Block[]) => {
  let blockData$ = blocks.map(block => {        
      return this.db.object(`/data/${block.blockOptions.dataID}`)
  });
  return Observable.combineLatest(blockData$,blocks, (bData,block) => {
    block.data = bData;
    return blocks;
  });
})

      

Template example

//what I want to happen
*ngFor="let block of blocks | async">
<dumb-component [blockData] = "block.data"></dumb-component>

//what I have to do now
*ngFor="let block of blocks | async">
<dumb-component [blockData] = "block.data | async"></dumb-component>

      

Thanks in advance, I feel very close any push in the right direction will be appreciated

+3


source to share


1 answer


You are close. This is just a call Observable.combineLatest

that needs some changes:

return this.db.list(`/user/${this.userId}/blocks`)
  .switchMap((blocks: Block[]) => {
    let arrayOf$ = blocks.map(block => {
      return this.db.object(`/data/${block.blockOptions.dataID}`)
    });
    return Observable.combineLatest(arrayOf$, (...arrayOfData) => {
      blocks.forEach((block, index) => {
        block.data = arrayOfData[index];
      });
      return blocks;
    });
  });

      

Your call blocks.map

returns an array of observables, so the combLatest signature you want to use is this one :

export function combineLatest<T, R>(
  array: ObservableInput<T>[],
  project: (...values: Array<T>) => R,
  scheduler?: IScheduler
): Observable<R>;

      



You pass it an array of observables and it calls your project function with the results. Just collect them into an array, repeat the command blocks

and assign the result to the appropriate index.


If you are using change detection ngrx

or OnPush

, you must make sure that mutations are not performed on the block array or the blocks themselves. To avoid mutations, the call combineLatest

would be something like this:

return Observable.combineLatest(arrayOf$, (...arrayOfData) => {
  return blocks.map((block, index) => {
    const data = arrayOfData[index];
    if (block.data !== data) {
        // If the block has no data or if the data has changed,
        // copy the block to avoid mutating it.
        return Object.assign({}, block, { data });
    }
    return block;
  }
});

      

+2


source







All Articles