0

I've got an Angular 13 application which is a sort of dashboard which monitors ever-changing data. The data comes from a Websocket and adds/updates records in the table as it comes in, live. The table has a few basic filter options (and I want to incorporate a sort option as well) which work statically, but when filters are applied, new data that comes in is not reflected in the filtered results.

My goal is to have the table update appropriately even if filters (and later, sorting) are applied.

The relevant code is as follows:

component.ts

myDataStream: Subject<DataStreamRecord[]> = new Subject();
records: Array<DataStreamRecord> = [];

ngOnInit(): void {

    // init stream listener
    this.myDataStream.subscribe({
      next: (data) => { 
        data.forEach(item => {
          // new item?
          var idx = this.records.findIndex(e => { return e.id === item.id });
          const now: any = new Date();
          const newItem = Object.assign({ ts: Math.trunc(now.getTime()/1000) }, item);
          if (idx >= 0) { // not new, update
            this.records[idx] = newItem;
          } else { // new item, add
            this.records.push(newItem);
            idx = this.records.length-1;
          }
        })
      },
      error: (err) => { console.error(err); },
      complete: () => { 'myDataStream complete' }
    });

}

component.html

<table class="table table-striped">
    <thead>
        <tr>...</tr>
    </thead>
    <tbody>
        <tr *ngFor="let record of records | recordFilter:form.value">...</tr>
        ...

recordfilter.pipe.ts

export class RecordFilterPipe implements PipeTransform {

  transform(list: DataStreamRecord[], filters: Object) {
    let selectedAttribute1: Attribute1 = _.get(filters, 'selectedAttribute1');
    let selectedAttribute2: Attribute2 = _.get(filters, 'selectedAttribute2');
    if (!selectedAttribute1 && !selectedAttribute2) return list;

    return list.filter(item => {
      // provider
      if (!selectedAttribute1) return item;
      return item.value1 === selectedAttribute1.value
    }).filter(item => {
      // race
      if (!selectedAttribute2) return item;
      return item.value2 === selectedAttribute2.value;
    })
  }

}

I am aware that the PipeTransform is returning a snapshot of the primary array, which is, of course, why new records added to the array are not reflected in the transformation. I anticipate that my approach needs editing, as I've reviewed other SO questions such as this one, and I'm getting the feeling that my Observable is not quite right (to support my use case, anyways), as this (and other) post refers to an Observable array, which is not what I have here...unless I do?

RDD Brian
  • 23
  • 4
  • Just have had time for a quick glance, but pipes are pure by default, which means that if their input doesn't change, they arent re-evaluated. Since you never re-assign `records` I suspect this may be the problem. – t.animal Mar 15 '22 at 11:30
  • @t.animal sp I would have to reconstruct the array according to the filter each time a new record comes in? – RDD Brian Mar 15 '22 at 11:42
  • 1
    That or you'd have to pass `pure: false` to the pipe's decorator. `@Pipe({name: 'recordFilter', pure: false})` – t.animal Mar 15 '22 at 12:43
  • @t.animal woah...that was easy. Thanks! – RDD Brian Mar 15 '22 at 17:47

0 Answers0