Мат-таблица с пагинатором, ошибка ExpressionChangedAfterItHasBeenChecked после восстановления индекса страницы

Я был бы рад немного помочь с моей текущей ошибкой, поскольку я пытаюсь найти решение уже несколько дней. Я хочу отобразить результат поиска, в котором может быть несколько сотен элементов. Я использую mat-table с mat-paginator, чтобы избежать слишком большого количества элементов на одной странице. Код выглядит так:

<mat-paginator #paginator [pageSize]="pageSize" [length]="resultsCount">
</mat-paginator>
<table [dataSource]="itemsDS" mat-table matSort matSortDisableClear>
  <!-- rows / columns defs, nothing too fancy -->
</table>

И ТС:

export class TableComponent implements OnInit {
  public itemsColumns: Array<string> = ["id", "name"];
  public itemsDS: MatTableDataSource<{
    id: number;
    name: string;
  }> = new MatTableDataSource<{ id: number; name: string }>();

  @ViewChild(MatPaginator, { static: false }) set paginator(
    paginator: MatPaginator
  ) {
    this.itemsDS.paginator = paginator;
  }

  @ViewChild(MatSort, { static: false }) set sort(sort: MatSort) {
    this.itemsDS.sort = sort;
  }

  constructor(private router: Router, private itemsService: ItemsService) {}

  ngOnInit() {
    console.log("Initializing items data");
    this.itemsDS.data = this.itemsService.items;
  }

  ngAfterViewInit() {
    if (this.itemsDS.paginator && this.itemsService.currentIndex > -1) {
      console.log("Restoring page index " + this.itemsService.currentIndex);
      this.itemsDS.paginator.pageIndex = this.itemsService.currentIndex;
    }
  }

  ngOnDestroy() {
    const currentPage = this.itemsDS.paginator.pageIndex;
    console.log("Saving page index on destroy " + currentPage);
    this.itemsService.currentIndex = currentPage;
  }

  // a few other functions like getters
}

Это сохраняет onDestroy текущую страницу, когда пользователь переходит к одному из элементов, и восстанавливает эту последнюю просмотренную страницу всякий раз, когда пользователь возвращается к результатам поиска.

Это работает нормально, но только когда индекс сохраненной страницы имеет значение 0. Всякий раз, когда пользователь переходит к элементу со страницы index > 1, Angular выдает ошибку ExpressionChangedAfterItHasBeenChecked. Мой код не содержит никаких изменений значения, которое можно было бы использовать где-нибудь выше в дереве компонентов. Так что я предполагаю, что это вопрос взаимодействия между mat-table и mat-paginator.

Я создал очень простой проект stackblitz, воспроизводящий это поведение, надеюсь, кто-то сможет найти, как обойти это ошибка. Обратите внимание, что при нажатии на item11 или item22 (первая страница) вы можете вернуться к списку без возникновения ошибки. Всякий раз, когда вы нажимаете на item33 (вторая страница), item55 или item66 (третья страница), консоль показывает ошибку при переходе обратно к списку.

Скомпилировано с последними библиотеками angular 8 (ядро 8.2.14 и материал 8.2.3).

Любая помощь будет оценена по достоинству.


person Wis    schedule 20.01.2020    source источник


Ответы (1)


Для полноты я добавляю сюда ответ, который я получил по этой проблеме репозитория материалов:

Хитрость заключается в том, чтобы восстановить индекс страницы внутри вызова setTimeout:

  ngAfterViewInit() {
    if (this.itemsDS.paginator && this.itemsService.currentIndex > -1) {
      setTimeout(() => {
        this.itemsDS.paginator.pageIndex = this.itemsService.currentIndex;
        this.itemsDS.paginator.page.emit({
          length: this.itemsDS.paginator.getNumberOfPages(),
          pageIndex: this.itemsService.currentIndex,
          pageSize: this.itemsDS.paginator.pageSize
        });
      });
    }
  }

Надеюсь, однажды это будет исправлено в Angular Material. Взгляните на эту проблему (которой уже несколько лет).

person Wis    schedule 10.02.2020