Problema:
Veo que muchos desarrolladores se enfrentan al problema con la clasificación con Groupable característica de Kendo UI - Angular. Cuando se trata de lidiar con una casilla de verificación para encabezados y columnas agrupables, es un verdadero dolor de cabeza. Vi que mis amigos estaban mutando su DOM o contexto HTML utilizando javascript tradicional en su proyecto angular, que no tiene sentido para mí. Por ejemplo,
document.getElementById('some_id').addAttribute('checked', 'checked');
Están marcando/desmarcando la casilla de verificación basándose en condiciones. Si usted está haciendo lo mismo, estoy escribiendo el artículo para usted. Sin mutar tu DOM, ¿puedes lograrlo?
Requisitos:
- Groupable debe agrupar tus columnas y mostrar las vistas apropiadas a los usuarios.
- Poner Checkboxes a la cabecera agrupada en el Kendo Grid y gestionar operaciones generales con esos checkboxes.
- Kendo Grid te permite mostrar datos de tablas agrupadas en una visualización simple y fácil de entender, también debe devolver resultados con una nueva estructura JSON una vez que cambias las columnas agrupables o sus órdenes.
- Cuando se seleccionan todas las casillas de verificación de la fila secundaria, debería seleccionar también su casilla de verificación principal (como se muestra en la imagen de cabecera anterior).
- Las funcionalidades existentes como ordenación de una/múltiples columnas, paginadores, paginaciones, Edición, Exportar plantillas de filas, y mostrar el número de filas por página, etc. deben funcionar.
Solución
- En primer lugar, entender cómo se puede configurar una cuadrícula kendo para sus necesidades. Visite aquí para explorar los fundamentos de KendoGrid y las dependencias de Package JSON. (Omite este paso si ya conoces KendoGrids y data bindings).
- Configure la directiva agrupable (Desarrollada por el equipo de Kendo UI para Angular) en su KendoGrid existente. Puede hacerlo siguiendo estos 3 pasos,
- Tendrás que configurar las opciones Group y Groupable en tu Grid.
- Necesitas gestionar el evento
groupChange
o el eventodataStateChange
emitido. (Kendo UI ya lo proporciona). - Necesitas agrupar los datos por ti mismo. Kendo Grid quiere que los datos agrupados sean una colección de GroupResults.
Aquí he preparado una demo para ilustrar cómo puedes conseguir tus requisitos.
TL; DR (Accede al siguiente enlace de forma gratuita*)
Stackblitz Editor | Live Demo Link | Github
Explicación:
Explicación de «Kendo Grid Groupable Column with checkbox Demo»
y sus archivos. Aclarará el concepto sobre su funcionamiento.
1. La lógica principal está escrita en el archivo app.component.ts
. Compruebe los comentarios escritos justo encima de cada método.
import { Component, ViewChildren, QueryList } from '@angular/core';
import { DataStateChangeEvent } from '@progress/kendo-angular-grid';
import { GroupResult, process, State } from '@progress/kendo-data-query';
export class pro {
Order_id: boolean = true;
ProductName: boolean = false;
constructor() {
//Object.assign(this,values); //if requres
}
}
@Component({
selector: 'my-app',
templateUrl: 'app.component.html'
})
export class AppComponent {
public state: State = {
skip: 0,
take: 4,
group: [{ field: 'Discontinued' }, { field: 'UnitPrice' }]
};
/** Sample data to bind with Kendo grid */
public data = [
{
Order_id: 1,
ProductName: 'Vodka',
UnitPrice: 19.0,
Quantity: 111,
Packages_available: 10,
Packages_status: 'Approved',
Discontinued: true
},
{
Order_id: 200,
ProductName: 'Coffee',
UnitPrice: 19.0,
Quantity: 12,
Packages_available: 12,
Packages_status: 'Approved',
Discontinued: false
},
{
Order_id: 300,
ProductName: 'Vodka',
UnitPrice: 10.0,
Quantity: 9999,
Packages_available: 222,
Packages_status: 'Approved',
Discontinued: false
},
{
Order_id: 116,
ProductName: 'Bisleri',
UnitPrice: 10.0,
Quantity: 9999,
Packages_available: 222,
Packages_status: 'Approved',
Discontinued: false
},
{
Order_id: 14,
ProductName: 'Milk',
UnitPrice: 22.0,
Quantity: 1131,
Packages_available: 2231,
Packages_status: 'Approved',
Discontinued: false
},
{
Order_id: 128,
ProductName: 'Red Wine',
UnitPrice: 22.0,
Quantity: 1131,
Packages_available: 2231,
Packages_status: 'Approved',
Discontinued: false
},
{
Order_id: 50,
ProductName: 'Mojito',
UnitPrice: 21.35,
Quantity: 1141,
Packages_available: 2241,
Packages_status: 'Approved',
Discontinued: false
},
{
Order_id: 600,
ProductName: 'Coffee',
UnitPrice: 25.0,
Quantity: 109,
Packages_available: 2252,
Packages_status: 'Approved',
Discontinued: false
},
{
Order_id: 700,
ProductName: 'Chai',
UnitPrice: 800.8,
Quantity: 108,
Packages_available: 2262,
Packages_status: 'Approved',
Discontinued: true
}
];
/**Process data for the kendogrid binding, it requireds value for [data] in this format. */
public gridData: any = process(this.data, this.state);
/** On change of data state, the below method will be called, update process of the kendo grid */
public dataStateChange(state: DataStateChangeEvent): void {
this.state = state;
this.gridData = process(this.data, this.state);
}
/** checkGroup will find the number of children and returns data accordingly, it will also change your JSON structure, console if you want to see what is changed there!*/
public checkGroup(group: GroupResult): void {
const leafItems = this.getGroupItems(group);
const shouldCheck = leafItems.some(item => !item.checked);
leafItems.forEach(item => (item.checked = shouldCheck));
}
/** Checking Groups with their JSON key values */
public isGroupResult(item: object): item is GroupResult {
return (
item.hasOwnProperty('items') &&
item.hasOwnProperty('value') &&
item.hasOwnProperty('field')
);
}
/** get data from Items (data after grouping the columns) or their respective child items */
public getGroupItems(group: GroupResult): any[] {
if (!group || !this.isGroupResult(group) || group.items.length === 0) {
return [];
}
if (!this.isGroupResult(group.items[0])) {
return group.items;
}
let descendants: any[] = [];
group.items.forEach(
(item: GroupResult) =>
(descendants = descendants.concat(this.getGroupItems(item)))
);
return descendants;
}
/** Manage checkbox leaf items if all children are selected, uncheck if not all of the checkboxes under the parent are not selected. */
public isGroupChecked(group: GroupResult): boolean {
const leafItems = this.getGroupItems(group);
return leafItems.every(item => item.checked);
}
}
view raw
Métodos importantes en app.component.ts
dataStateChange()
- Al cambiar el estado de los datos, se llamará al siguiente método, proceso de actualización de la rejilla kendocheckGroup()
- checkGroup encontrará el número de hijos y devuelve los datos en consecuencia, también cambiará su estructura JSON, ¡consola si quieres ver lo que ha cambiado allí!isGroupResult()
- Comprobación de Grupos con sus valores clave JSONgetGroupItems()
- Obtener datos de Items (datos después de agrupar las columnas) o sus respectivos items hijosisGroupChecked()
- Gestionar los ítems de la hoja de casillas de verificación si todos los hijos están seleccionados, desmarcar si no todas las casillas de verificación bajo el padre no están seleccionadas.
2. Archivo html para renderizar y data-binding con kendo grid, con ejemplo de checkbox - app.component.html
<kendo-grid [data]="gridData" [pageSize]="state.take" [skip]="state.skip" [sort]="state.sort" [group]="state.group"
[sortable]="{ mode: 'multiple' }" [pageable]="true" [groupable]="{ showFooter: true }"
(dataStateChange)="dataStateChange($event)">
<kendo-grid-column field="Order_id" title="Product ID" width="150">
<ng-template kendoGridHeaderTemplate>
<input
type="checkbox"
(change)="checkGroup(group)"
class="k-checkbox"
id="selectAllCheckboxPrintId"
name="selectAllCheckboxOption"
title="Select All "
/>
<label class="k-checkbox-label" for="selectAllCheckboxPrintId"
>Select All</label>
</ng-template>
<ng-template kendoGridCellTemplate let-dataItem>
<input
type="checkbox"
[checked]="dataItem.checked"
[(ngModel)]="dataItem.checked"
class="customCheckBtn"
id="id_{{ field }}_{{ value }}"
[name]="dataItem.Order_id"
/>
</ng-template>
</kendo-grid-column>
<kendo-grid-column field="ProductName" title="Product Name">
<ng-template kendoGridGroupHeaderTemplate let-group let-aggregates let-title="title" let-field="field"
let-value="value" let-dataItem="dataItem">
<strong
><input
type="checkbox"
(change)="checkGroup(group)"
[checked]="isGroupChecked(group)"
class="customCheckBtn"
id="id_{{ field }}_{{ value }}"
/> Count: {{ value }}</strong>
</ng-template>
<ng-template kendoGridGroupHeaderTemplate let-group let-aggregates let-title="title" let-field="field"
let-value="value" let-dataItem="dataItem">
<strong
><input
type="checkbox"
(change)="checkGroup(group)"
[checked]="isGroupChecked(group)"
class="customCheckBtn"
id="id_{{ field }}_{{ value }}"
/> Count: {{ value }}</strong>
</ng-template>
</kendo-grid-column>
<kendo-grid-column field="UnitPrice" title="Unit Price" width="200">
<ng-template kendoGridGroupHeaderTemplate let-group let-title="title" let-field="field" let-value="value"
let-dataItem="dataItem">
<strong
><input
type="checkbox"
(change)="checkGroup(group)"
[checked]="isGroupChecked(group)"
class="customCheckBtn"
id="id_{{ field }}_{{ value }}"
/> Price: {{ group.value }}</strong>
</ng-template>
</kendo-grid-column>
<kendo-grid-column field="Quantity" title="Quantity" width="200">
<ng-template kendoGridGroupHeaderTemplate let-group let-title="title" let-field="field" let-value="value"
let-dataItem="dataItem">
<strong
><input
type="checkbox"
(change)="checkGroup(group)"
[checked]="isGroupChecked(group)"
class="customCheckBtn"
id="id_{{ field }}_{{ value }}"
/> Quantity: {{ group.value }}</strong>
</ng-template>
</kendo-grid-column>
<kendo-grid-column field="Packages_available" title="Packages Available" width="200">
<ng-template kendoGridGroupHeaderTemplate let-group let-title="title" let-field="field" let-value="value"
let-dataItem="dataItem">
<strong
><input
type="checkbox"
(change)="checkGroup(group)"
[checked]="isGroupChecked(group)"
class="customCheckBtn"
id="id_{{ field }}_{{ value }}"
/> Packages Available: {{ group.value }}</strong>
</ng-template>
</kendo-grid-column>
<kendo-grid-column field="Packages_status" title="Packages Status" width="200">
<ng-template kendoGridGroupHeaderTemplate let-group let-title="title" let-field="field" let-value="value"
let-dataItem="dataItem">
<strong
><input
type="checkbox"
(change)="checkGroup(group)"
[checked]="isGroupChecked(group)"
class="customCheckBtn"
id="id_{{ field }}_{{ value }}"
/> Packages Status: {{ group.value }}</strong>
</ng-template>
</kendo-grid-column>
<kendo-grid-column field="Discontinued" width="120">
<ng-template kendoGridCellTemplate let-dataItem>
{{ dataItem.Discontinued ? 'Yes' : 'No' }}
</ng-template>
<ng-template kendoGridGroupHeaderTemplate let-group let-aggregates let-title="title" let-field="field"
let-value="value" let-dataItem="dataItem">
<strong
><input
type="checkbox"
(change)="checkGroup(group)"
[checked]="isGroupChecked(group)"
class="customCheckBtn"
id="id_{{ field }}_{{ value }}"
/>
{{ group.value ? 'Discontinued' : 'Not Discontinued' }}</strong>
</ng-template>
</kendo-grid-column>
</kendo-grid>
Observa [group]="state.group
“ , [groupable]=”{ showFooter: true }
“ y (dataStateChange)=”dataStateChange($event)
» usando estas 3 opciones puedes configurar una rejilla kendo para que esté lista para agrupar las columnas.
- Donde quieras checkbox, solo agrega el evento change para llamar al método checkGroup del archivo «.ts» -
(change)=«checkGroup(group)»
- Aquí
[(ngModel)]="dataItem.checked
» se encargará de todas las casillas de verificación dadas para las filas o encabezados hijos y padres respectivamente.
¡¡¡Listo!!! Bingo 👏👏👏, ¡Lo has conseguido!
Espero que esta fácil solución te ayude seguro.
Necesito Tu Favor (No es obligatorio):
Referencias
- Telerik - Documentación de la librería Kendo UI para Angular
- Github Gists | Para representar el código de manera bien estructurada
- Stackblitz - Kendo Grid Groupable Demo | Preparado por el Autor Rakshit Shah