Blazor : créer un composant avec une datagrid (2/3) : le tri

Blazor sqli 2

Dans le précédent article, nous avons exploré la création d’un composant Blazor réutilisable avec l’implémentation concrète d’une datagrid avec pagination. Dans cette seconde partie, je vais reprendre le composant précédent et y ajouter le tri des colonnes, ce qui permet de voir les composants imbriqués. 

Cet article se basant sur le projet réalisé dans l’article précédent, je vous invite à le lire avant de continuer celui-ci. 

Ajout du tri dans la datagrid

Nous allons maintenant ajouter à notre datagrid la possibilité de trier les colonnes par ordre croissant et par ordre décroissant. Pour cela, nous allons ajouter un nouveau composant qui sera en charge de la gestion des headers. 

1. Comme pour la datagrid, faites un clic droit sur le projet Ajouter > Nouvel élément, puis choisissez Composant Razor et donnez-lui le nom de DataGridColumn.razor. 

Comme pour le premier composant, il y aura plusieurs parties. La première avec les informations de rendu, et la seconde avec les fonctions C#.  

2. Remplacez le contenu du fichier par ceci : 

<th>@DisplayColumnName</th> 

 

@functions { 

    [Parameter] 

    public string DisplayColumnName { get; set; } = string.Empty; 

} 

Ici on indique simplement que l’on passe en paramètre du composant le nom de la colonne à afficher. Et dans le th, on affiche ce nom. 

 

3. Dans le fichier FetchData.razorde l’application, remplacez le contenu de BlazorDataGridColumn par :  

<BlazorDataGridColumn> 

    <DataGridColumn DisplayColumnName="Date"></DataGridColumn> 

    <DataGridColumn DisplayColumnName="Temp. (C)"></DataGridColumn> 

    <DataGridColumn DisplayColumnName="Temp. (F)"></DataGridColumn> 

    <DataGridColumn DisplayColumnName="Summary"></DataGridColumn> 

</BlazorDataGridColumn> 

Pour le moment, le rendu est exactement le même qu’avec le <th>..</th>, mais on voit que l’on a imbriqué un composant dans un autre. Il est maintenant possible d’enrichir le composant DatagridColumn afin de lui faire faire beaucoup plus de choses, comme trier nos colonnes. Maintenant que l’on a la base du composant, on va justement pouvoir commencer à gérer ce fameux tri. 

 

Comme pour le composant précédent, on va ajouter en haut de la page @typeparam TItem qui va nous permettre de gérer une liste de TItem. 

On va ensuite aborder une nouvelle notion que sontles paramètres en cascadeCes paramètres permettent à un composant père d’envoyer un paramètre à un composant fils. 

 

4. Ajoutez dans le fichier dans la partie functions : 

[CascadingParameter] 

public BlazorDataGrid<TItemBlazorDataTable { get; set; }  

Ici on passe en paramètre le composant père, ce qui va nous permettre de récupérer des informations comme la liste. Dans le fichierRazorDatagrid.razor il faut passer le composant en paramètre. 

5. Remplacez 

@BlazorDataGridColumn 

Par 

         <CascadingValue Value="this"> 

                @BlazorDataGridColumn 

            </CascadingValue> 

6. L’utilisation de typeparam nous oblige aussi à passer la liste en paramètre du composant pour récupérer le type. Ajoutons donc également  

[Parameter] 

public IEnumerable<TItem> Items { get; set; } 

Maintenant, il faut mettre en place le mécanisme de tri des colonnes. Pour cela, nous allons utiliser une fonction qui prend en paramètre le nom réel de la colonne à trier, et non le nom d’affichage. Par exemple, je peux avoir un objet avec une propriété string Name {get; set;}. Le nom de la colonne sera Name alors que le nom d’affichage peut très bien être Nom. 

 

7. Nous allons donc devoir ajouter quelques paramètres dans notre composant pour gérer efficacement le tri. Tout d’abord, comme je l’ai déjà dit, il faut gérer le nom de la colonne. Nous allons donc naturellement ajouter un paramètre dans le composant : 

[Parameter] 

public string ColumnName { get; set; } 

 

8.Puis il faudra savoir si on fait un tri ascendant ou descendant. C’est là qu’intervient une nouvelle variable : 

private bool IsSortedAscending; 

 

9. Il faut également savoir si on trie la même colonne ou pas. On va pour cela ajouter une variable au niveau de la datagrid. Dans le fichier BlazorDataGrid.razor, ajoutez : 

public string CurrentSortColumn; 

Nos nouvelles variables sont en place, on peut donc commencer à écrire la fonction permettant le tri.  

 

10. Retournons dans le fichier DataGridColumn.razor et ajoutons cette nouvelle fonction : 

private void SortTable(string columnName) 

    { 

        if (columnName != BlazorDataTable.CurrentSortColumn) 

        { 

            BlazorDataTable.Items = BlazorDataTable.Items.OrderBy(x => x.GetType().GetProperty(columnName).GetValue(x, null)).ToList(); 

 

            BlazorDataTable.CurrentSortColumn = columnName; 

            IsSortedAscending = true; 

 

        } 

        else 

        { 

            if (IsSortedAscending) 

            { 

                BlazorDataTable.Items = BlazorDataTable.Items.OrderByDescending(x => x.GetType().GetProperty(columnName).GetValue(x, null)).ToList(); 

            else 

            { 

                BlazorDataTable.Items = BlazorDataTable.Items.OrderBy(x => x.GetType().GetProperty(columnName).GetValue(x, null)).ToList(); 

            } 

 

            IsSortedAscending = !IsSortedAscending; 

        } 

    } 

 

11. Regardons un peu dans le détail ce que fait cette fonction. D’abord on vérifie si on trie une nouvelle colonne ou la même colonne. 

if (columnName != BlazorDataTable.CurrentSortColumn) 

Par défaut, le tri sur une nouvelle colonne est ascendant. On va donc faire une requête orderbysur la liste de notre élément parent (BlazorDataTable.Items) passé en paramètre via l’annotation [CascadingParameter]. 

Notre fonction est générique puisqu’on ne se sait pas à l’avance quelle colonne on va trier. C’est pour ça que l’on passe le nom de la colonne en paramètre. x.GetType().GetProperty(columnName).GetValue(x, null)) nous permet de requêter sur la bonne colonne. 

Si cependant c’est la même colonne que l’on trie, il faut savoir dans quel ordre le faire. On vérifie donc la valeur de IsSortedAscending pour effectuer un OrderBy ou un OrderByDescending. Et on pense ensuite à inverser la valeur de ce booléen pour trier dans le sens inverse si on tri la même colonne. (IsSortedAscending = !IsSortedAscending; ) 

 

12. Il faut maintenant adapter le modèle de notre header. Remplacez : 

<th>@DisplayColumnName</th 

Par 

<th> 

    <span @onclick="@(() => SortTable(ColumnName))">@DisplayColumnName</span> 

</th> 

Au clic sur le nom de la colonne, on appelle la fonction Sortable qui se charge de faire le tri. Pour tester, il faut modifier un peu l’appel dans l’application. 

 

13. Dans FetchData.razor modifiez la datagrid comme ceci : 

<BlazorDataGrid Items="@forecastsPageSize="4"> 

        <BlazorDataGridColumn> 

            <DataGridColumn Items="@forecastsColumnName="Date" DisplayColumnName="Date"></DataGridColumn> 

            <DataGridColumn Items="@forecastsColumnName="TemperatureCDisplayColumnName="Temp. (C)"></DataGridColumn> 

            <DataGridColumn Items="@forecastsColumnName="TemperatureFDisplayColumnName="Temp. (F)"></DataGridColumn> 

            <DataGridColumn Items="@forecastsColumnName="SummaryDisplayColumnName="Summary"></DataGridColumn> 

        </BlazorDataGridColumn> 

        <GridRow> 

            <td>@context.Date.ToShortDateString()</td> 

            <td>@context.TemperatureC</td> 

            <td>@context.TemperatureF</td> 

            <td>@context.Summary</td> 

        </GridRow> 

    </BlazorDataGrid> 

 

Et là, quand on clique sur le nom Il ne se passe rien. En effet, il va falloir signaler à l’élément parent que la liste a changé et qu’il doit faire un rafraîchissement. Nous allons utiliser pour cela un service partagé qui sera disponible pour le père et pour le fils. 

14. Ajoutez un nouveau dossier dans le projet du composant. Clic droit sur le projet puis Ajouter > Nouveau dossier puis appelez ce nouveau dossier Services. 

Visuel blazor 1

15. Ajoutez ensuite une nouvelle classe dans le dossier. Clic droit sur le dossier, Ajouter > Classe, puis appelez cette classe cs.

Visuel blazor 2

 

Cette classe va contenir un événement et une méthode qui nous permettra de faire un rafraîchissement du parent.

using System; 

namespace BlazorComponent.Services

{    

public class AppState    

{        

public event Action RefreshRequested;        

public void CallRequestRefresh()        

{            

RefreshRequested?.Invoke();        

}    

}

}

 

Nous allons maintenant, par injection de dépendance, ajouter cette classe dans nos deux composants.

 

16. Ajoutez- en haut des fichiersrazor et BlazorDataGrid.razor

 @using Services

@inject AppState AppState

Dans le parent, c’est-à-dire dans le fichier BlazorDatagrid, il faut créer une fonction de rafraîchissement et s’abonner à l’évènement RefreshRequested avec comme application, la fonction de rafraîchissement.

Commençons par créer la fonction de rafraichissement.

 

17. Ajoutez :

private void RefreshMe()

    {

        StateHasChanged();

        updateList(curPage);

    }

On indique qu’un changement a eu lieu et on appelle la fonction de mise à jour avec la page courante.

 

18.Il faut également s’abonner à l’évènement. Dans la fonction OnInitializedAsync ajoutez :

AppState.RefreshRequested += RefreshMe;

Tout est prêt du côté du père, il faut maintenant se tourner du côté du fils.

A chaque évolution de la de la liste, il faudra appeler la méthode AppState.CallRequestRefresh();.

 

19. Nous pouvons donc modifier la fonction Sortable de la manière suivante :

private void SortTable(string columnName)

    {

        if (columnName != BlazorDataTable.CurrentSortColumn)

        {

            BlazorDataTable.Items = BlazorDataTable.Items.OrderBy(x => x.GetType().GetProperty(columnName).GetValue(x, null)).ToList();




            BlazorDataTable.CurrentSortColumn = columnName;

            IsSortedAscending = true;

            AppState.CallRequestRefresh();

        }

        else

        {

            if (IsSortedAscending)

            {

                BlazorDataTable.Items = BlazorDataTable.Items.OrderByDescending(x => x.GetType().GetProperty(columnName).GetValue(x, null)).ToList();

            }

            else

            {

                BlazorDataTable.Items = BlazorDataTable.Items.OrderBy(x => x.GetType().GetProperty(columnName).GetValue(x, null)).ToList();

            }

            AppState.CallRequestRefresh();

            IsSortedAscending = !IsSortedAscending;

        }

    }

Pour tester le tri, nous devons malgré tout déclarer notre service afin que l’injection de dépendance puisse s’effectuer.

 

20. Dans le projet de l’application, ouvrez le fichier cs et ajoutez dans la fonction ConfigureServices :

services.AddScoped<AppState, AppState>();

Il faudra probablement ajouter également en haut de page

        using BlazorComponent.Services;

Nous pouvons maintenant tester notre tri. A ce stade, le tri s’effectue correctement. Seulement, ajouter un indicateur visuel montrant quelle colonne est triée, et dans quel sens, serait un vrai plus. Ne tardons pas et ajoutons cette fonctionnalité.

 

21. Ouvrez le fichier razoret ajoutez une fonction pour gérer le style :

 private string GetSortStyle(string columnName)    

{        

if (BlazorDataTable.CurrentSortColumn != columnName)        

{            

return string.Empty;        

}        

if (IsSortedAscending)        

{            

return "oi-arrow-thick-top";        

}        

else        

{           

 return "oi-arrow-thick-bottom";       

 }    

}

 

Le premier if (if (BlazorDataTable.CurrentSortColumn != columnName)) permet de savoir si on se trouve sur la colonne que l’on souhaite trier. Si ce n’est pas le cas, on supprime le marqueur.

Sinon on regarde dans quel sens on tri pour afficher le marqueur adéquat.

 

22. Il ne reste qu’à afficher ce marqueur sur la colonne et pour cela, il suffit d’ajouter <span class= »oi @(GetSortStyle(ColumnName)) »></span> dans notre modèle.

<th>

        <span @onclick="@(() => SortTable(ColumnName))">@DisplayColumnName</span>

        <span class="oi @(GetSortStyle(ColumnName))"></span>

    </th>

Si on lance à nouveau l’application, on peut constater qu’une flèche vient indiquer la colonne triée et le sens de tri.

 

Visuel blazor 3

 

Conclusion

Voilà, notre datagrid peut maintenant être triée et paginée. Nous avons vu ensemble l’utilisation des paramètres cascadés ainsi que les services partagés permettant la communication entre nos composants. Il est facile d’imbriquer des composants, et cela offre une utilisation encore plus riche. Dans le prochain article, nous verrons comment ajouter des filtres sur notre datagrid.

 

0 commentaires

votre commentaire

Se joindre à la discussion ?
Vous êtes libre de contribuer !

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Inscription newsletter

Ne manquez plus nos derniers articles !