Operações de dados remotos do Angular Grid
O Ignite UI for Angular Grid suporta operações remotas de dados, como virtualização remota, classificação remota, filtragem remota e outras. Isso permite que o desenvolvedor execute essas tarefas em um servidor, recupere os dados produzidos e os exiba no Grid.
Angular Grid Remote Data Operations Overview Example
Por padrão, o Grid usa sua própria lógica para executar operações de dados. Você pode executar essas tarefas remotamente e alimentar os dados resultantes para a Grade aproveitando determinadas entradas e eventos, que são expostos pela Grade.
Remote Virtualization
O IgxGrid suporta o cenário em que os blocos de dados são solicitados de um serviço remoto, expondo o comportamento implementado naigxForOf diretiva que ele usa internamente.
Para utilizar esse recurso, você precisa se inscrever nadataPreLoad Saída para que você faça a solicitação apropriada com base nos argumentos recebidos, assim como para definir o público IgxGrid PropriedadetotalItemCount com as respectivas informações vindas do serviço.
<igx-grid #grid [data]="remoteData | async" [autoGenerate]="false"
(dataPreLoad)="processData(false)"
(sortingDone)="processData(true)">
<igx-column [field]="'ProductID'" [sortable]="true"></igx-column>
<igx-column [field]="'ProductName'" [sortable]="true"></igx-column>
<igx-column [field]="'UnitPrice'" [dataType]="'number'" [formatter]="formatCurrency" [sortable]="true"></igx-column>
</igx-grid>
public ngAfterViewInit() {
this.grid.isLoading = true;
this._remoteService.getData(this.grid.virtualizationState, this.grid.sortingExpressions[0], true, (data) => {
this.grid.totalItemCount = data['@odata.count'];
this.grid.isLoading = false;
});
}
public processData(reset) {
if (this.prevRequest) {
this.prevRequest.unsubscribe();
}
this._prevRequest = this._remoteService.getData(this.grid.virtualizationState,
this.grid.sortingExpressions[0], reset, () => {
...
this.cdr.detectChanges();
});
}
Ao solicitar dados, você precisa utilizar aIForOfState interface, que fornece asstartIndex propriedades e.chunkSize
Note
O primeirochunkSize sempre será 0 e deve ser determinado por você com base no cenário específico da aplicação.
Remote Virtualization Demo
Infinite Scroll
Um design popular para cenários que exigem buscar dados por blocos de um ponto final é o chamado scroll infinito. Para grades de dados, ele é caracterizado pelo aumento contínuo dos dados carregados acionados pelo usuário final que rola até o fundo. Os próximos parágrafos explicam como você pode usar a API disponível para alcançar facilmente rolagemIgxGrid infinita.
Para implementar o scroll infinito, você precisa buscar os dados em blocos. Os dados que já foram buscados devem ser armazenados localmente e você precisa determinar o comprimento de um bloco e quantos blocos existem. Você também precisa acompanhar o último índice visível de linhas de dados na grade. Dessa forma, usando asstartIndex propriedades e,chunkSize você pode determinar se o usuário rola para cima e você precisa mostrar dados já buscados ou descer e buscar mais dados do ponto final.
A primeira coisa a fazer é usar ongAfterViewInit gancho do ciclo de vida para buscar o primeiro pedaço dos dados. Definir atotalItemCount propriedade é importante, pois permite que a grade redimensione corretamente a barra de rolagem.
public ngAfterViewInit() {
this._remoteService.loadDataForPage(this.page, this.pageSize, (request) => {
if (request.data) {
this.grid.totalItemCount = this.page * this.pageSize;
this.grid.data = this._remoteService.getCachedData({startIndex: 0, chunkSize: 10});
this.totalItems = request.data['@odata.count'];
this.totalPageCount = Math.ceil(this.totalItems / this.pageSize);
this.grid.isLoading = false;
}
});
}
Além disso, você precisa assinar adataPreLoad saída, para poder fornecer os dados necessários pela grade quando ela tentar exibir um pedaço diferente, em vez do que está carregado atualmente. No gerenciador de eventos, você precisa determinar se busca novos dados ou retorna dados que já estão cacheados localmente.
public handlePreLoad() {
const isLastChunk = this.grid.totalItemCount ===
this.grid.virtualizationState.startIndex + this.grid.virtualizationState.chunkSize;
// when last chunk reached load another page of data
if (isLastChunk) {
if (this.totalPageCount === this.page) {
this.grid.data = this._remoteService.getCachedData(this.grid.virtualizationState);
return;
}
this.page++;
this.grid.isLoading = true;
this._remoteService.loadDataForPage(this.page, this.pageSize, (request) => {
if (request.data) {
this.grid.totalItemCount = Math.min(this.page * this.pageSize, this.totalItems);
this.grid.data = this._remoteService.getCachedData(this.grid.virtualizationState);
this.grid.isLoading = false;
}
});
} else {
this.grid.data = this._remoteService.getCachedData(this.grid.virtualizationState);
}
}
Infinite Scroll Demo
Remote Sorting/Filtering
Para fornecer ordenação e filtragem remotas, você precisa assinar odataPreLoad,sortingExpressionsChange efilteringExpressionsTreeChange para que você faça o pedido apropriado com base nos argumentos recebidos, assim como definir o público IgxGrid PropriedadetotalItemCount com as respectivas informações vindas do serviço.
Também vamos aproveitar a função rxjs debounceTime, que emite um valor do Observável de origem somente após um determinado período de tempo passar sem outra emissão de fonte. Dessa forma, a operação remota só será acionada quando o tempo especificado tiver passado, sem que o usuário a interrompa.
const DEBOUNCE_TIME = 300;
...
public ngAfterViewInit() {
...
this.grid.dataPreLoad.pipe(
debounceTime(DEBOUNCE_TIME),
takeUntil(this.destroy$)
).subscribe(() => {
this.processData();
});
this.grid.filteringExpressionsTreeChange.pipe(
debounceTime(DEBOUNCE_TIME),
takeUntil(this.destroy$)
).subscribe(() => {
this.processData(true);
});
this.grid.sortingExpressionsChange.pipe(
debounceTime(DEBOUNCE_TIME),
takeUntil(this.destroy$)
).subscribe(() => {
this.processData();
});
}
Quando ordenação e filtragem remotas são fornecidas, geralmente não precisamos da ordenação e filtragem embutidas da grade. Podemos desativá-las definindo assortStrategy entradas efilterStrategy da grade para eNoopSortingStrategy asNoopFilteringStrategy respectivas instâncias.
<igx-grid #grid [data]="remoteData | async" [height]="'500px'" [width]="'100%'" [autoGenerate]='false'
[filterStrategy]="noopFilterStrategy"
[sortStrategy]="noopSortStrategy"
[allowFiltering]="true">
...
</igx-grid>
public noopFilterStrategy = NoopFilteringStrategy.instance();
public noopSortStrategy = NoopSortingStrategy.instance();
Note
Quando dados remotos são solicitados, a operação de filtragem diferencia maiúsculas de minúsculas.
Remote Sorting/Filtering Demo
Você pode ver o resultado do código acima no início deste artigo na seção Demonstração.
Unique Column Values Strategy
Os itens da lista dentro da caixa de diálogo de Filtragem de Estilo Excel representam os valores únicos para a respectiva coluna. A Grade gera esses valores com base em sua fonte de dados por padrão. No caso de filtragem remota, os dados da grade não contêm todos os dados do servidor. Para fornecer os valores únicos manualmente e carregá-los sob demanda, podemos aproveitar a entrada dauniqueColumnValuesStrategy Grade. Essa entrada é, na verdade, um método que fornece três argumentos:
- column: a respectiva instância da coluna.
- filteringExpressionsTree: a árvore de expressões de filtragem, que é reduzida com base na respectiva coluna.
- done- Retorno de chamada que deve ser chamado com os valores de coluna recém-gerados quando eles são recuperados do servidor.
O desenvolvedor pode gerar manualmente os valores de coluna exclusivos necessários com base nas informações, fornecidas pela coluna e pelos argumentos filteringExpressionsTree e, em seguida, invocar o retorno de chamada done.
Note
Quando auniqueColumnValuesStrategy entrada é fornecida, o processo padrão de geração de valores únicos no filtro estilo Excel não será usado.
<igx-grid #grid1 [data]="data" [filterMode]="'excelStyleFilter'" [uniqueColumnValuesStrategy]="columnValuesStrategy">
...
</igx-grid>
public columnValuesStrategy = (column: ColumnType,
columnExprTree: IFilteringExpressionsTree,
done: (uniqueValues: any[]) => void) => {
// Get specific column data.
this.remoteValuesService.getColumnData(column, columnExprTree, uniqueValues => done(uniqueValues));
}
Unique Column Values Strategy Demo
Para fornecer um modelo de carregamento personalizado para o filtro no estilo Excel, podemos usar aigxExcelStyleLoading diretiva:
<igx-grid [data]="data" [filterMode]="'excelStyleFilter'" [uniqueColumnValuesStrategy]="columnValuesStrategy">
...
<ng-template igxExcelStyleLoading>
Loading ...
</ng-template>
</igx-grid>
Remote Paging
O recurso de paginação pode operar com dados remotos. Para demonstrar isso, vamos primeiro declarar nosso serviço que será responsável pela busca de dados. Precisaremos da contagem de todos os itens de dados para calcular a contagem de páginas. Essa lógica será adicionada ao nosso serviço.
@Injectable()
export class RemotePagingService {
public remoteData: BehaviorSubject<any[]>;
public dataLenght: BehaviorSubject<number> = new BehaviorSubject(0);
public url = 'https://www.igniteui.com/api/products';
constructor(private http: HttpClient) {
this.remoteData = new BehaviorSubject([]) as any;
}
public getData(index?: number, perPage?: number): any {
let qS = '';
if (perPage) {
qS = `?$skip=${index}&$top=${perPage}&$count=true`;
}
this.http
.get(`${this.url + qS}`).pipe(
map((data: any) => data)
).subscribe((data) => this.remoteData.next(data));
}
public getDataLength(): any {
return this.http.get(this.url).pipe(
map((data: any) => data.length)
);
}
}
Após declarar o serviço, precisamos criar um componente, que será responsável pela construção do Grid e assinatura de dados.
export class RemotePagingGridSample implements OnInit, AfterViewInit, OnDestroy {
public data: Observable<any[]>;
private _dataLengthSubscriber;
constructor(private remoteService: RemoteService) {}
public ngOnInit() {
this.data = this.remoteService.remoteData.asObservable();
this._dataLengthSubscriber = this.remoteService.getDataLength().subscribe((data) => {
this.totalCount = data;
this.grid1.isLoading = false;
});
}
public ngOnDestroy() {
if (this._dataLengthSubscriber) {
this._dataLengthSubscriber.unsubscribe();
}
}
}
Agora podemos escolher entre criar nosso próprio modelo de paginação personalizado ou usar o padrão que elesigx-paginator fornecem. Vamos primeiro dar uma olhada no que é necessário para configurar paginação remota usando o template padrão de paginação.
Remote paging with default template
Se você quiser usar o modelo padrão de paginação, precisa definir a propriedade dototalRecords paginador, só assim a grade poderá calcular o número total da página com base no total de registros remotos. Ao realizar uma paginação remota, o Paginador passa para a Grade apenas os dados da página atual, então a grade não tentará paginar a fonte de dados fornecida. Por isso devemos definir a propriedade dopagingMode Grid como GridPagingMode.remote. Também é necessário assinar eventospagingDone de ORperPageChange para obter os dados do seu serviço remoto, depende do caso de uso qual evento será utilizado.
<igx-grid #grid1 [data]="data | async" [isLoading]="isLoading" [pagingMode]="mode">
<igx-column field="ID"></igx-column>
...
<igx-paginator [(page)]="page" [(perPage)]="perPage" [totalRecords]="totalCount"
(pagingDone)="paginate($event.current)">
</igx-paginator>
</igx-grid>
public totalCount = 0;
public data: Observable<any[]>;
public mode = GridPagingMode.remote;
public isLoading = true;
@ViewChild('grid1', { static: true }) public grid1: IgxGridComponent;
private _dataLengthSubscriber;
public set perPage(val: number) {
this._perPage = val;
this.paginate(0);
}
public ngOnInit() {
this.data = this.remoteService.remoteData.asObservable();
this._dataLengthSubscriber = this.remoteService.getDataLength().subscribe((data: any) => {
this.totalCount = data;
this.grid1.isLoading = false;
});
}
public ngAfterViewInit() {
const skip = this.page * this.perPage;
this.remoteService.getData(skip, this.perPage);
}
public paginate(page: number) {
this.page = page;
const skip = this.page * this.perPage;
const top = this.perPage;
this.remoteService.getData(skip, top);
}
Remote Paging with custom igx-paginator-content
Quando definimos um conteúdo personalizado para paginador, precisamos definir o conteúdo de forma a obter os dados apenas para a página solicitada e para passar os parâmetros corretos de pular e superior para o serviço remoto, de acordo com a página eperPage os itens selecionados. Vamos usar o<igx-paginator> para facilitar nossa configuração de exemplo, junto com osIgxPageSizeSelectorComponent eIgxPageNavigationComponent que foram introduzidos -igx-page-sizevamos adicionar o menu suspenso por página, o rótulo eigx-page-nav os botões e etiquetas de ação de navegação.
<igx-paginator #paginator
[totalRecords]="totalCount"
[(page)]="page"
[(perPage)]="perPage"
[selectOptions]="selectOptions"
(pageChange)="paginate($event)"
(perPageChange)="perPageChange($event)">
<igx-paginator-content>
<igx-page-size></igx-page-size>
[This is my custom content]
<igx-page-nav></igx-page-nav>
</igx-paginator-content>
</igx-paginator>
@ViewChild('grid1', { static: true }) public grid1: IgxGridComponent;
private _perPage = 15;
private _dataLengthSubscriber: { unsubscribe: () => void; } | undefined;
constructor(private remoteService: RemotePagingService) { }
public ngAfterViewInit() {
this.grid1.isLoading = true;
this.remoteService.getData(0, this.perPage);
}
public paginate(page: number) {
this.page = page;
const skip = this.page * this.perPage;
const top = this.perPage;
this.remoteService.getData(skip, top);
}
public perPageChange(perPage: number) {
const skip = this.page * perPage;
const top = perPage;
this.remoteService.getData(skip, top);
}
Note
Para que a Paginação Remota seja configurada corretamente,GridPagingMode.Remote deve ser definida:
<igx-grid #grid1 [data]="data | async" width="100%" height="580px" [pagingMode]="mode"></igx-grid>
...
public mode = GridPagingMode.Remote;
A última etapa será declarar o conteúdo do paginador com base em seus requisitos.
<igx-paginator-content>
<igx-page-size></igx-page-size>
[This is my custom content]
<igx-page-nav></igx-page-nav>
</igx-paginator-content>
Após todas as alterações acima, o seguinte resultado será alcançado.
Remote Paging with custom paginator
Em alguns casos, você pode querer definir seu próprio comportamento de paginação e é quando podemos aproveitar o modelo de paginação e adicionar nossa lógica personalizada junto com ele. Vamos estender o exemplo de paginação remota para demonstrar isso:
Abaixo você encontrará os métodos que definimos para implementar nossas própriasnext ações eprevious ações de página.
@ViewChild('grid1', { static: true }) public grid1: IgxGridComponent;
public ngAfterViewInit() {
this.grid1.isLoading = true;
this.remoteService.getData(0, this.perPage);
}
public nextPage() {
this.firstPage = false;
this.page++;
const skip = this.page * this.perPage;
const top = this.perPage;
this.remoteService.getData(skip, top);
if (this.page + 1 >= this.totalPages) {
this.lastPage = true;
}
this.setNumberOfPagingItems(this.page, this.totalPages);
}
public previousPage() {
this.lastPage = false;
this.page--;
const skip = this.page * this.perPage;
const top = this.perPage;
this.remoteService.getData(skip, top);
if (this.page <= 0) {
this.firstPage = true;
}
this.setNumberOfPagingItems(this.page, this.totalPages);
}
public paginate(page: number, recalculate = false) {
this.page = page;
const skip = this.page * this.perPage;
const top = this.perPage;
if (recalculate) {
this.totalPages = Math.ceil(this.totalCount / this.perPage);
}
this.setNumberOfPagingItems(this.page, this.totalPages);
this.remoteService.getData(skip, top);
this.buttonDeselection(this.page, this.totalPages);
}
Remote Paging with Batch editing
Com os exemplos até agora, esclarecemos como configurar o IgxGrid com dados remotos. Agora, vamos nos concentrar em habilitar a edição em lote para a grade seguindo o tópico/guia de edição em lote.
Antes de continuar com o exemplo, é bom esclarecer o caso de uso atual. Quando a paginação é feita no servidor, a grade contém os dados apenas para a página atual e se adicionarmos novas linhas, as linhas recém-adicionadas (com Edição em Lote) serão concatenadas com os dados atuais que a grade contém. Portanto, se o servidor não retornar dados para uma determinada página, a fonte de dados da grade será composta apenas pelas linhas recém-adicionadas, que a grade paginará com base nas configurações de paginação definidas (página, por página).
public ngOnInit() {
this._dataLengthSubscriber = this.remoteService.getDataLength().subscribe((data) => {
this.totalCount = data;
this._recordOnServer = data;
this._totalPagesOnServer = Math.floor(this.totalCount / this.perPage);
this.grid1.isLoading = false;
});
}
Para lidar com esse caso de uso adequadamente, precisamos implementar alguma lógica personalizada. Primeiro, precisamos saber o número total de registros que estão no servidor. Diante disso, calculamos o número total de páginas de dados no servidor (vejathis._totalPagesOnServer) e, com base em seu valor, implementaremos a lógica de paginação personalizada.
public paginate(page: number) {
this.grid1.endEdit(true);
if (page > this._totalPagesOnServer) {
if (this.page !== this._totalPagesOnServer) {
const skipEl = this._totalPagesOnServer * this.perPage;
this.remoteService.getData(skipEl, this.perPage);
}
this.page = page - this._totalPagesOnServer;
this.page = page;
return;
} else {
this.page = 0;
}
this.page = page;
const skip = this.page * this.perPage;
this.remoteService.getData(skip, this.perPage);
}
Como você pode ver no método de paginação, uma lógica de paginação personalizada é executada, baseada no_totalPagesOnServer valor.
Paginação remota com demonstração de edição em lote
Known Issues and Limitations
- Quando a grade não
primaryKeytem um set definido e cenários de dados remotos são ativados (ao paginar, ordenar, filtrar, rolar requisições de gatilho para um servidor remoto para recuperar os dados a serem exibidos na grade), uma linha perderá o seguinte estado após a conclusão de uma solicitação de dados:- Seleção de linha
- Expandir/recolher linha
- Edição de linha
- Fixação de linha
- Em cenários de dados remotos, quando a grade tem um
primaryKeyargumento set,rowSelectionChanging.oldSelectionevento não conterá o objeto de dados da linha completa para as linhas que estão atualmente fora da visualização de dados. Nesse caso,rowSelectionChanging.oldSelectionobjeto conterá apenas uma propriedade, que é oprimaryKeycampo. Para o restante das linhas, atualmente na visualização de dados,rowSelectionChanging.oldSelectionconterá os dados da linha inteira.
API References
Additional Resources
- Paginação
- Visão geral da grade
- Virtualização e desempenho
- Filtragem
- Classificação
- Resumos
- Movimentação de Colunas
- Fixação de coluna
- Redimensionamento de colunas
- Escolha