Réaliser un composant Blazor réutilisable : Exemple avec une datagrid (partie 3/3 : Filtres)

Réaliser un composant Blazor réutilisable : Exemple avec une datagrid (partie 3/3 : Filtres)

Cette troisième partie va se concentrer sur l’ajout de filtres sur le composant Datagrid. Je vais repartir du composant déjà produit jusque-là. Si ce n’est pas fait, je vous invite à lire mes deux précédents articles ce qui vous permettra de suivre plus aisément cette partie. A la fin de la partie 2, nous avions un composant affichant une datagrid paginée et triée. Il est temps de pouvoir filtrer les colonnes.

Filtrer les colonnes

Pour réaliser le filtre, nous allons ajoutons une zone de saisie dans chaque colonne. La saisie déclenchera l’appel d’une fonction qui modifie la liste en fonction du filtre.

Par ailleurs, il faudra que ce filtre tienne compte des valeurs de chaque colonne.

Pour réaliser un filtre tenant compte des valeurs des zones de saisie de chaque colonne, il faut introduire un dictionnaire au niveau du composant parent. Ce dictionnaire stockera le nom de la colonne et la valeur du filtre.

Dans le fichier BlazorDataGrid.razor ajoutez

public Dictionary<string, string> FilterDictionary { get; set; }

Et dans la fonction OnInitializedAsync on initialise le dictionnaire :

FilterDictionary = new Dictionary<string, string>();

Dans le fichier DataGridColumn.razor, il faut une fonction de filtre.

Ajoutez

private void Filtering(string value, string columnName)
    {
        BlazorDataTable.FilterDictionary[columnName] = value;

        foreach (var column in BlazorDataTable.FilterDictionary)
        {
            BlazorDataTable.Items = BlazorDataTable.Items.Where(x => x.GetType().GetProperty(column.Key).GetValue(x, null).ToString().IndexOf(column.Value, StringComparison.OrdinalIgnoreCase) >= 0).ToList();
        }

        AppState.CallRequestRefresh();
    }

Cette fonction prend deux paramètres. Le nom de la colonne dans laquelle vient d’être saisi un filtre et la valeur saisie.

La première instruction consiste à ajouter dans le tableau (ou modifier si la clé existe déjà) la valeur associée à la colonne.

Ensuite on itère sur chaque colonne présente dans le dictionnaire pour affiner le filtre.

A la fin, la liste parente est modifiée avec uniquement les valeurs correspondantes à l’ensemble des filtres.

Et la dernière instruction, tout comme avec le tri, indique au parent qu’il faut mettre à jour son affichage.

La fonction est en place, il faut à présent ajouter la zone de saisie du filtre.

Dans la balise th, ajoutez

<br />
 <input width="70" @oninput="@((ui) => { Filtering((string)ui.Value, ColumnName); })" />

On place une balise input qui sera notre zone de saisie, et sur l’évènement oninput (à chaque fois que l’on tape quelque chose dans la zone de saisie) on appelle la fonction de filtrage avec les paramètres requis.

On a donc :

<th>
        <span @onclick="@(() => SortTable(ColumnName))">@DisplayColumnName</span>
        <span class="oi @(GetSortStyle(ColumnName))"></span>
        <br />
        <input width="70" @oninput="@((ui) => { Filtering((string)ui.Value, ColumnName); })" />
    </th>

A l’exécution on constate que le filtre fonctionne bien. Il y a malgré tout un léger petit souci. Une fois filtré, on ne peut pas revenir en arrière. En effet, si j’enlève un caractère saisi dans l’une des zones de filtre, je ne reviens pas à l’état filtré précédent. Ceci s’explique simplement parce que notre liste filtrée ne contient plus tous les éléments. Il faut donc introduire un mécanisme de retour arrière afin de pouvoir ajuster le filtre sans perte de données.

Nous allons donc ajouter une variable dans le fichier DataGridColumn.razor.

private string PreviousValue { get; set; } = string.Empty;

Cette variable va nous permettre de connaitre la précédente valeur tapée pour la colonne. Si sa taille est inférieure à la nouvelle valeur, c’est qu’on fait un retour arrière et qu’il faut reprendre une liste plus étendue.

Dans notre fonction de filtrage, on va ajouter un test :

if (value.Length < PreviousValue.Length)
        {
            BlazorDataTable.Items = Items;
        }

On reprend la liste de départ si on enlève des caractères.

Et à la fin on met à jour la valeur de la variable PreviousValue :

PreviousValue = value;

La fonction de filtrage ressemble maintenant à ça :


private void Filtering(string value, string columnName)
    {
        BlazorDataTable.FilterDictionary[columnName] = value;

        if (value.Length < PreviousValue.Length)
        {
            BlazorDataTable.Items = Items;
        }

        foreach (var column in BlazorDataTable.FilterDictionary)
        {
            BlazorDataTable.Items = BlazorDataTable.Items.Where(x => x.GetType().GetProperty(column.Key).GetValue(x, null).ToString().IndexOf(column.Value, StringComparison.OrdinalIgnoreCase) >= 0).ToList();
        }

        AppState.CallRequestRefresh();
        PreviousValue = value;
    }

On constate maintenant que le filtre revient bien en arrière si on enlève des caractères.

Conclusion

L’utilisation de composant imbriqué permet d’enrichir considérablement le comportement des éléments. On a pu constater dans cet exemple qu’il est facile d’ajouter un filtre sur une colonne en améliorant simplement son composant. Et l’imbrication n’a pas de limite, on peut donc réaliser des composants complexe permettant de répondre à des besoins complexe.

Blazor permet ainsi de réaliser facilement des composants réutilisables en s’appuyant uniquement sur du code C#. Il n’est ainsi plus obligatoire d’avoir recours à du javascript. Et comme le montre cet exemple, on peut s’appuyer sur la richesse du .net pour faire des pages web interactives.

Laisser un commentaire