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

Time:04-25

i have a problem... with angular virtual scroll. i tried too many solutions. but i can't resolve the problem. when i added new item to the favoriteList, i pushed the new item to the front of the favoriteList. but there are no changes to the list of the rendered view. how can i change the view when new item added?

my problem: https://stackblitz.com/edit/angular-cdk-scroll-bug-vifffd?file=src/app/app.component.ts

CodePudding user response:

I haven't worked with this virtual scroll before, but it looks like I found your solution. I noticed that when you reassign the value of favoriteList inside your remove method, it works and re-renders the content, therefore I did the same inside your addItem method, i.e. changed your 'adding' logic to:

this.favoriteList = [newItem, ...this.favoriteList];

Here's the forked Stackblitz with the working solution - https://stackblitz.com/edit/angular-cdk-scroll-bug-ibuggp?file=src/app/app.component.ts

CodePudding user response:

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