Operaciones de datos remotos de Angular Grid
El Ignite UI for Angular Grid admite operaciones de datos remotas como virtualización remota, clasificación remota, filtrado remoto y otros. Esto permite al desarrollador realizar estas tareas en un servidor, recuperar los datos que se producen y mostrarlos en la cuadrícula.
Angular Grid Remote Data Operations Overview Example
De forma predeterminada, Grid utiliza su propia lógica para realizar operaciones de datos. Puede realizar estas tareas de forma remota y alimentar los datos resultantes a Grid aprovechando ciertas entradas y eventos, que están expuestos por Grid.
Remote Virtualization
El IgxGrid soporta el escenario en el que los fragmentos de datos se solicitan a un servicio remoto, exponiendo el comportamiento implementado en laigxForOf directiva que utiliza internamente.
Para utilizar esta función, necesitas suscribirte a ladataPreLoad Resultados para que hagas la solicitud adecuada basada en los argumentos recibidos, así como para establecer el público IgxGrid PropiedadtotalItemCount con la información correspondiente procedente del servicio.
<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();
});
}
Al solicitar datos, necesitas utilizar laIForOfState interfaz, que proporciona lasstartIndex propiedades ychunkSize de .
Note
La primerachunkSize siempre será 0 y debería determinarla tú según el escenario específico de la aplicación.
Remote Virtualization Demo
Infinite Scroll
Un diseño popular para escenarios que requieren obtener datos por bloques desde un punto final es el llamado scroll infinito. En las cuadrículas de datos, se caracteriza por un aumento continuo de los datos cargados que se desencadena cuando el usuario final desplaza hasta el final. Los siguientes párrafos explican cómo puedes usar la API disponible para lograr fácilmente desplazamientoIgxGrid infinito.
Para implementar el scroll infinito, tienes que obtener los datos en bloques. Los datos que ya se han recuperado deberían almacenarse localmente y tienes que determinar la longitud de un fragmento y cuántos fragmentos hay. También tienes que llevar un registro del último índice de filas de datos visible en la cuadrícula. De este modo, usando lasstartIndex propiedades ychunkSize, puedes determinar si el usuario sube y tienes que mostrarle datos ya obtenidos o desplazarse hacia abajo y obtener más datos desde el punto final.
Lo primero que hay que hacer es usar elngAfterViewInit gancho del ciclo de vida para obtener el primer fragmento de los datos. Configurar latotalItemCount propiedad es importante, ya que permite que la cuadrícula tenga el tamaño correcto de su barra de desplazamiento.
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;
}
});
}
Además, tienes que suscribirte a ladataPreLoad salida para poder proporcionar los datos necesarios para la red cuando intente mostrar un fragmento diferente, en lugar del que está cargado actualmente. En el gestor de eventos, tienes que decidir si buscas nuevos datos o devuelves datos que ya están almacenados en caché 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 proporcionar ordenación y filtrado a distancia, necesitas suscribirte a ladataPreLoad,sortingExpressionsChange yfilteringExpressionsTreeChange para que hagas la solicitud adecuada basada en los argumentos recibidos, así como para establecer el público IgxGrid PropiedadtotalItemCount con la información correspondiente procedente del servicio.
También aprovecharemos la función rxjs debounceTime, que emite un valor desde el observable fuente solo después de que haya pasado un periodo de tiempo determinado sin otra emisión de fuente. De este modo, la operación remota se activará solo cuando haya transcurrido el tiempo especificado sin que el usuario la interrumpa.
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();
});
}
Cuando se proporciona ordenación y filtrado remotos, normalmente no necesitamos la ordenación y filtrado incorporados de la cuadrícula. Podemos desactivarlos configurando lassortStrategy entradas yfilterStrategy de la cuadrícula a lasNoopSortingStrategy instancias respectivasNoopFilteringStrategy y .
<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
Cuando se solicitan datos remotos, la operación de filtrado distingue entre mayúsculas y minúsculas.
Remote Sorting/Filtering Demo
Puede ver el resultado del código anterior al comienzo de este artículo en la sección Demostración.
Unique Column Values Strategy
Los elementos de la lista dentro del diálogo de Filtrado de Estilo Excel representan los valores únicos de la columna correspondiente. La Cuadrícula genera estos valores por defecto basándose en su fuente de datos. En caso de filtrado remoto, los datos de la red no contienen todos los datos del servidor. Para proporcionar los valores únicos manualmente y cargarlos bajo demanda, podemos aprovechar la entrada deuniqueColumnValuesStrategy la Red. Esta entrada es en realidad un método que proporciona tres argumentos:
- columna: la instancia de columna respectiva.
- filteringExpressionsTree: el árbol de expresiones de filtrado, que se reduce según la columna respectiva.
- done: devolución de llamada que debe llamarse con los valores de columna recién generados cuando se recuperan del servidor.
El desarrollador puede generar manualmente los valores de columna únicos necesarios en función de la información proporcionada por la columna y los argumentos filteringExpressionsTree y luego invocar la devolución de llamada hecha.
Note
Cuando se proporciona launiqueColumnValuesStrategy entrada, no se utilizará el proceso generador de valores únicos por defecto en el filtrado estilo Excel.
<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 proporcionar una plantilla de carga personalizada para el filtrado en estilo Excel, podemos usar laigxExcelStyleLoading directiva:
<igx-grid [data]="data" [filterMode]="'excelStyleFilter'" [uniqueColumnValuesStrategy]="columnValuesStrategy">
...
<ng-template igxExcelStyleLoading>
Loading ...
</ng-template>
</igx-grid>
Remote Paging
La función de localización puede funcionar con datos remotos. Para demostrar esto, primero declaremos que nuestro servicio será responsable de la obtención de datos. Necesitaremos el recuento de todos los elementos de datos para poder calcular el recuento de páginas. Esta lógica se agregará a nuestro servicio.
@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)
);
}
}
Después de declarar el servicio, necesitamos crear un componente que será responsable de la construcción de la red y la suscripción de datos.
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();
}
}
}
Ahora podemos elegir entre configurar nuestra propia plantilla de paginación personalizada o usar la predeterminada que proporcionen.igx-paginator Veamos primero qué es necesario para configurar la paginación remota usando la plantilla de paginación predeterminada.
Remote paging with default template
Si quieres usar la plantilla de paginación predeterminada necesitas establecer la propiedad deltotalRecords paginador, solo entonces la cuadrícula podrá calcular el número total de página basándose en registros remotos totales. Al realizar una paginación remota, el paginador pasará a la cuadrícula solo los datos de la página actual, por lo que la cuadrícula no intentará paginar la fuente de datos proporcionada. Por eso deberíamos poner la propiedad depagingMode Grid en GridPagingMode.remote. Además, es necesario suscribirse apagingDone eventos de ORperPageChange para obtener los datos de tu servicio remoto; depende del caso de uso qué evento se utilize.
<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
Cuando definimos el contenido de un paginador personalizado, necesitamos definir el contenido de manera que los datos solo correspondan a la página solicitada y que pasemos los parámetros correctos de salto y superior al servicio remoto según la página y los elementosperPage seleccionados. Vamos a usar el<igx-paginator> para facilitar nuestra configuración de ejemplo, junto con losIgxPageSizeSelectorComponent queIgxPageNavigationComponent se han introducido,igx-page-size añadiremos el desplegable por página y etiquetar, yigx-page-nav añadiremos los botones y etiquetas de la acción de navegación.
<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 la paginación remota esté configurada correctamente,GridPagingMode.Remote debe establecerse:
<igx-grid #grid1 [data]="data | async" width="100%" height="580px" [pagingMode]="mode"></igx-grid>
...
public mode = GridPagingMode.Remote;
El último paso será declarar el contenido del paginador según sus requisitos.
<igx-paginator-content>
<igx-page-size></igx-page-size>
[This is my custom content]
<igx-page-nav></igx-page-nav>
</igx-paginator-content>
Después de todos los cambios anteriores, se logrará el siguiente resultado.
Remote Paging with custom paginator
En algunos casos, es posible que desee definir su propio comportamiento de paginación y aquí es cuando podemos aprovechar la plantilla de paginación y agregar nuestra lógica personalizada junto con ella. Vamos a ampliar el ejemplo de paginación remota para demostrar esto:
A continuación encontrarás los métodos que hemos definido para implementar nuestras propiasnext acciones yprevious acciones 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
Con los ejemplos hasta ahora aclaramos cómo configurar el IgxGrid con datos remotos. Ahora, centrémonos en habilitar la edición por lotes para la cuadrícula siguiendo el tema/guía Edición por lotes.
Antes de continuar con el ejemplo, es bueno aclarar el caso de uso actual. Cuando se realiza la paginación en el servidor, la cuadrícula contiene los datos solo para la página actual y si agregamos nuevas filas, las filas recién agregadas (con edición por lotes) se concatenarán con los datos actuales que contiene la cuadrícula. Por lo tanto, si el servidor no devuelve datos para una página determinada, la fuente de datos de la cuadrícula estará compuesta únicamente por las filas recién agregadas, que la cuadrícula paginará según la configuración de paginación definida (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 manejar este caso de uso correctamente, necesitamos implementar algo de lógica personalizada. Primero, tenemos que conocer el número total de registros que hay en el servidor. Dado esto, calculamos el número total de páginas de datos en el servidor (ver)this._totalPagesOnServer y, basándonos en su valor, implementaremos la lógica de paginación 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 puedes ver en el método de paginación, se realiza una lógica de paginación personalizada, basada en el_totalPagesOnServer valor.
Paginación remota con demostración de edición por lotes
Known Issues and Limitations
- Cuando la cuadrícula no
primaryKeytiene un sistema fijo y los escenarios de datos remotos están habilitados (al paginar, ordenar, filtrar o desplazar las solicitudes de disparo a un servidor remoto para recuperar los datos que se mostrarán en la cuadrícula), una fila perderá el siguiente estado tras completar una solicitud de datos:- Selección de fila
- Fila Expandir/contraer
- Edición de filas
- Fijación de filas
- En escenarios de datos remotos, cuando la cuadrícula tiene un
primaryKeyargumento set,rowSelectionChanging.oldSelectionevento no contendrá el objeto de datos completo de fila para las filas que actualmente están fuera de la vista de datos. En este caso,rowSelectionChanging.oldSelectionobject contendrá solo una propiedad, que es elprimaryKeycampo. Para el resto de las filas, actualmente en la vista de datos,rowSelectionChanging.oldSelectioncontendrán los datos completos de la fila.
API References
Additional Resources
- Paginación
- Descripción general de la cuadrícula
- Virtualización y rendimiento
- Filtración
- Clasificación
- resúmenes
- Columna en movimiento
- Fijación de columnas
- Cambio de tamaño de columna
- Selección