angular virtual scroll doesn't re-render the list when list item added

Viewed 135
1 Answers

Angular Input sees the changes when the value changes, but in our case the input is not of primitive type then he will only know the reference of the array.

This is the virtual scroll input:

  /** The DataSource to display. */
  @Input()
  get cdkVirtualForOf(): DataSource<T> | Observable<T[]> | NgIterable<T> | null | undefined {
    return this._cdkVirtualForOf;
  }
  set cdkVirtualForOf(value: DataSource<T> | Observable<T[]> | NgIterable<T> | null | undefined) {
    this._cdkVirtualForOf = value;
    if (isDataSource(value)) {
      this._dataSourceChanges.next(value);
    } else {
      // If value is an an NgIterable, convert it to an array.
      this._dataSourceChanges.next(
        new ArrayDataSource<T>(isObservable(value) ? value : Array.from(value || [])),
      );
    }
  }

  _cdkVirtualForOf: DataSource<T> | Observable<T[]> | NgIterable<T> | null | undefined;

In your case, it would be best to create a new class and implement DataSource

something like that:

export class CustomDataSource<T extends { id: number }> extends DataSource<T> {
  private _dataSource: BehaviorSubject<T[]>;

  constructor() {
    super();

    this._dataSource = new BehaviorSubject<T[]>([]);
  }

  connect(): Observable<readonly T[]> {
    return this._dataSource.asObservable();
  }

  disconnect(): void {}

  add(item: T): void;
  add(item: T[]): void;
  add(item: T | T[]): void {
    const currentValue = this._dataSource.value;
    const items = Array.isArray(item) ? item : [item];
    const nextValue = currentValue.concat(items);

    this._dataSource.next(nextValue);
  }

  remove(id: T['id']): void {
    const currentValue = this._dataSource.value;
    const nextValue = currentValue.filter(item => item.id !== id);

    this._dataSource.next(nextValue);
  }
}

stackblitz implementation

Related