voir Stackblitz ici .
Je veux afficher un affichage en direct de callCount
lorsque rowCallback()
est appelé lorsque chacune des cellules de Kendo Grid est vérifiée.
Je m'attends à ce que le numéro de callCount
final soit 12 (c'est-à-dire 3 lignes x 4 cellules chacune = 12).
J'obtiens l'erreur ExpressionChangedAfterItHasBeenCheckedError
classique. Rien d'utile n'a été mentionné sur le site Telerik: https://www.telerik.com/kendo-angular-ui/components/grid/api/GridComponent/#toc-rowclass
Code pour plus de commodité:
import { Component, ViewEncapsulation } from '@angular/core'; import { RowClassArgs } from '@progress/kendo-angular-grid'; @Component({ selector: 'my-app', encapsulation: ViewEncapsulation.None, styles: [` .k-grid tr.even { background-color: #f45c42; } .k-grid tr.odd { background-color: #41f4df; } `], template: ` <kendo-grid [data]="gridData" [rowClass]="rowCallback"> </kendo-grid> <div>{{callCount}}</div> <!-- Double bind to show the current number --> ` }) export class AppComponent { public gridData: any[] = products; public callCount: number = 0; public rowCallback = (context: any) => { this.callCount++; // Incrementing the number } } const products = [{ "ProductID": 1, "ProductName": "Chai", "UnitPrice": 18.0000, "Discontinued": true }, { "ProductID": 2, "ProductName": "Chang", "UnitPrice": 19.0000, "Discontinued": false }, { "ProductID": 3, "ProductName": "Chang", "UnitPrice": 28.0000, "Discontinued": false } ];
4 Réponses :
Je ne pense pas que vous devriez utiliser la méthode rowClass pour calculer le nombre de cellules dans la grille kendo.
Comme spécifié dans la documentation de rowClass, vous devez utiliser pour définir dynamiquement le nom de la classe Css. Je pense que vous pouvez facilement atteindre votre objectif en utilisant les méthodes ci-dessous de base sur les scénarios suivants:
Cas 1: Lorsque vous connaissez le nombre de colonnes que vous souhaitez afficher sur la grille Kendo, vous pouvez créer une propriété qui contiendra ses valeurs et l'utiliser dans l'expression du modèle comme suit:
import { Component, ViewEncapsulation } from '@angular/core'; import { RowClassArgs } from '@progress/kendo-angular-grid'; @Component({ selector: 'my-app', encapsulation: ViewEncapsulation.None, styles: [` .k-grid tr.even { background-color: #f45c42; } .k-grid tr.odd { background-color: #41f4df; } `], template: ` <kendo-grid [data]="gridData"> </kendo-grid> <div>{{ columnCount * gridData.length }}</div> <!-- Double bind to show the current number--> ` }) export class AppComponent { public gridData: any[] = products; public callCount: number = 0; public readonly columnCount = Object.keys(gridData); } const products = [{ "ProductID": 1, "ProductName": "Chai", "UnitPrice": 18.0000, "Discontinued": true }, { "ProductID": 2, "ProductName": "Chang", "UnitPrice": 19.0000, "Discontinued": false }, { "ProductID": 3, "ProductName": "Chang", "UnitPrice": 28.0000, "Discontinued": false } ];
Cas-2: Lorsque vous n'êtes pas conscient du nombre de colonnes que vous souhaitez afficher sur la grille Kendo, vous pouvez le calculer dynamiquement sur la charge de votre composant:
import { Component, ViewEncapsulation } from '@angular/core'; import { RowClassArgs } from '@progress/kendo-angular-grid'; @Component({ selector: 'my-app', encapsulation: ViewEncapsulation.None, styles: [` .k-grid tr.even { background-color: #f45c42; } .k-grid tr.odd { background-color: #41f4df; } `], template: ` <kendo-grid [data]="gridData"> </kendo-grid> <div>{{ columnCount * gridData.length }}</div> <!-- Double bind to show the current number--> ` }) export class AppComponent { public gridData: any[] = products; public callCount: number = 0; public readonly columnCount = 4; // let say grid has 4 column (known prior) } const products = [{ "ProductID": 1, "ProductName": "Chai", "UnitPrice": 18.0000, "Discontinued": true }, { "ProductID": 2, "ProductName": "Chang", "UnitPrice": 19.0000, "Discontinued": false }, { "ProductID": 3, "ProductName": "Chang", "UnitPrice": 28.0000, "Discontinued": false } ];
Dans tous les cas, vous pouvez trouver le nombre de colonnes avant de rendre la grille et vous pouvez l'utiliser pour calculer le nombre de grille.
Vous pouvez utiliser le rappel setTimeout
dans vos méthodes rowCallback
. Pour éviter ExpressionChangedAfterItHasBeenCheckedError
erreur ExpressionChangedAfterItHasBeenCheckedError
.
public rowCallback = (context: any) => { setTimeout(() => { this.callCount++; // Incrementing the number }); }
Comme l'indique l'erreur, vous définissez la valeur d'une propriété dans la vue après la fin du cycle de vie angulaire, ( AfterContentHasBeenChecked )
Considérez ce scénario
Vous définissez la valeur de
callCount = 0
, dans votre html vous avez<div> 0 </div>
Le contenu est vérifié.
La 1ère ligne est chargée
Maintenant, nous mettons à jourcallCount = 1
et html<div> 1 </div>
Cela déclenche la détection des changements et donc l'erreur
Si nous voulons implémenter l'approche ci-dessus, nous devrons informer anguar de ce changement pour lequel nous pouvons utiliser ChangeDetectorRef
. Essayons maintenant d'implémenter ce qui précède avec ceci
Vous définissez la valeur de
callCount = 0
, dans votre html vous avez<div> 0 </div>
Détection de changement de déclenchement Le contenu est vérifié.
La 1ère ligne est chargée
Maintenant, nous mettons à jourcallCount = 1
et html<div> 1 </div>
Détection de changement de déclenchement La 2ème rangée est chargée
Maintenant, nous mettons à jourcallCount = 2
et html<div> 2 </div>
Détection de changement de déclenchement La 3ème rangée est chargée
Maintenant, nous mettons à jourcallCount = 3
et html<div> 3 </div>
Détection de changement de déclenchement La 1ère ligne est chargée
Maintenant, nous mettons à jourcallCount = 4
et html<div> 4 </div>
Détection de changement de déclenchement La 2ème rangée est chargée
Maintenant, nous mettons à jourcallCount = 5
et html<div> 5 </div>
Détection de changement de déclenchement La 3ème rangée est chargée
Maintenant, nous mettons à jourcallCount = 6
et html<div> 6 </div>
Détection de changement de déclenchement
...
Cette boucle ne se terminera jamais et angulaire lancera une erreurMaximum stack reached
Ce qui précède est ce que Angular essaie de vous avertir. Cela indique qu'il y a un problème avec votre approche
Vous aurez besoin d'un moyen de déterminer le nombre de lignes avant que le contenu ne soit vérifié
L'option la plus simple sera de compter le nombre de produits et de le multiplier par le maximum du nombre de propriétés dans chaque article
<button (click)='updateValue()'>Update</button> <kendo-grid [data]="gridData | async" [rowClass]="rowCallback"> </kendo-grid> <div>{{ callCount | async }}</div> <!-- Double bind to show the current number -->
Dans le code ci-dessus, j'utilise BehaviorSubject
pour stocker les données en tant Observable
. De cette façon, nous pouvons utiliser le piping
et l'opérateur map
pour obtenir la propriété length
des produits (qui sera essentiellement le nombre de lignes de la table)
Dans le html, nous pouvons utiliser un tube asynchrone pour nous abonner à ces Observables
import { BehaviorSubject, combineLatest, Observable, of } from "rxjs"; import { map } from "rxjs/operators"; // Create a new Observable using Behaviour subject to store current products private gridDataSubject$ = new BehaviorSubject(products); public gridData: Observable<any[]> = this.gridDataSubject$.asObservable(); // Extract the row count being length of the products array private rowCount: Observable<number> = this.gridData.pipe( map(({ length }) => length) ); // Extract column count being the Maximum of the product with the highest number of properties private columCount: Observable<number> = this.gridData.pipe( map((data) => data.map(item => Object.keys(item).length)), map(data => Math.max(...data)) ); // Define to total calls being rows X columns public callCount: Observable<number> = combineLatest([this.columCount, this.rowCount]).pipe(map(([row, column]) => row * column)) public rowCallback = (context: any) => {}; updateValue() { this.gridDataSubject$.next(products2); } public rowCallback = (context: any) => {}; updateValue() { this.gridDataSubject$.next(products2) }
Essayez de cliquer sur le bouton, cela mettra à jour le tableau et le nombre de lignes
Le problème est que vous mettez à jour la vue après AfterViewChecked
La seule solution à votre implémentation que je vois est d'utiliser ChangeDetectorRef :
export class AppComponent { public gridData: any[] = products; public callCount: number = 0; public rowCallback = (context: any) => { this.callCount++; // Incrementing the number this.changeDetectorRef.detectChanges(); } constructor(private changeDetectorRef: ChangeDetectorRef) {} }
Erreur: Maximum call stack size exceeded
C'est parce que rowCallback est appelé à chaque détection de changement. Trouvons une solution appropriée à votre problème. Cela ne devrait pas être si compliqué. Quel est votre objectif avec la tâche?
Pouvez-vous également ajouter une capture d'écran de l'erreur de console?
J'ai ajouté une réponse à votre requête et je ne pense pas que vous devriez utiliser la liaison de propriété (liaison rowClass) pour incrémenter une autre propriété de composant. C'est une règle de base angulaire que l'état du composant ne doit pas changer pendant la liaison de propriété.