MatSort и MatPaginator не работают без setTimeOut - PullRequest
0 голосов
/ 26 октября 2018

У меня есть данные, поступающие из конечной точки и помещенные в MatTableDataSource. Я смог заставить его работать для MatSort и MatPaginator, но мне нужно было использовать setTimeOut, что, кажется, не является правильным способом сделать это. Если я уберу это, он будет жаловаться, что «Не удается прочитать свойство вида undefined», что, как я предполагал, связано с тем, что оно еще не инициализировано.

Я также пробовал:

  • чтобы переместить его в afterviewinit, но данные были загружены после afterviewinit вызывается, так что он все еще не работает
  • использование this.changeDetectorRef.detectChanges () после this.datasource = новый ... тоже не работает

Это мой текущий код (который работает, но использует settimeout)

<div *ngIf="!isLoading">
    <div *ngFor="let record of renderedData | async" matSort>

    // ... some html to show the 'record'

    <mat-paginator #paginator
        [pageSizeOptions]="[5, 10, 20]">
    </mat-paginator>
</div>

Компонент

export class ResultsComponent implements OnInit, OnDestroy, AfterViewInit {
    dataSource: MatTableDataSource<any> = new MatTableDataSource();
    renderedData: Observable<any>;

    @ViewChild(MatPaginator) paginator: MatPaginator;
    @ViewChild(MatSort) sort: MatSort;

    constructor(some service) {}

    ngOnInit() {
        const accountId = someOtherService.getAccountId();
        this.someService.getData(accountId)
            .subscribe((myData) => {
                    this.dataSource = new MatTableDataSource(myData);

                    // it won't work properly if it is not wrapped in timeout
                    setTimeout(() => {
                        this.dataSource.paginator = this.paginator;
                        this.sort.sort(<MatSortable>({id: 'created_on', start: 'desc'}));
                        this.dataSource.sort = this.sort;
                    });

                    this.renderedData = this.dataSource.connect();
                }
            });
    }

    ngAfterViewInit() {
    }

    ngOnDestroy(): void {
        if (this.dataSource) { this.dataSource.disconnect(); }
    }
}

Приведенный выше код работает для меня, я просто ищу правильный способ не использовать settimeout, если это возможно.

1 Ответ

0 голосов
/ 26 октября 2018

Здесь есть несколько проблем с синхронизацией жизненного цикла, и если подумать, это правильно.

MatSort является частью представления, поэтому он не «готов» во время OnInit - он не определен. Так что попытка его использования приводит к ошибке.

MatSort готов в AfterViewInit, но все усложняется тем фактом, что вам необходимо «применить» сортировку к источнику данных после выполнения сортировки, и это вызывает изменения в представлении с помощью RenderedData, которая является ' подключен к источнику данных. В результате вы получаете ExpressionChangedAfterItHasBeenCheckedError, поскольку жизненный цикл инициализации представления не завершен, но вы уже пытаетесь изменить его.

Таким образом, вы не можете выполнить сортировку, пока представление не будет готово, и вы не сможете применить сортировку, когда получите уведомление о том, что представление готово. Единственное, что вы можете сделать, это дождаться окончания жизненного цикла инициализации компонента. И вы можете сделать это с помощью setTimeout ().

Я не думаю, что есть какой-либо способ обойти обе эти проблемы без setTimeout (), поэтому в этом случае не имеет значения, вызываете ли вы его из OnInit или AfterViewInit.

Пара других замечаний по вашему коду:

Вам не нужно создавать новый экземпляр MatTableDataSource в вашей подписке. Вы можете присвоить данные результатов уже созданному источнику данных:

this.dataSource.data = myData;

Это освобождает вас от необходимости впоследствии подключать отображаемые данные к источнику данных, так что вы можете сделать это при инициализации источника данных:

dataSource: MatTableDataSource<any> = new MatTableDataSource();
renderedData: Observable<any> = this.dataSource.connect();
...