Datatables jquery avec ASP.NET MVC 5 – 2ème partie

Dans le premier volet consacré au Datatables Jquery dans un projet ASP.NET MVC 5, nous avons pu voir comment intégrer facilement ce plugin qui permet l’affichage de données sous forme de tableau dans un projet web ASP.NET MVC. Dans cette 2ème partie, nous irons plus loin dans notre démarche d’intégration de ce plugin et nous verrons comment ça se présente dans un vrai projet.

Dans un contexte d’entreprise, nous nous retrouvons à gérer des données grandissantes dans le temps (en tout cas nous devons le prévoir). Ces informations sont, en général, stockées dans des bases de données. Ainsi, il nous faudra charger nos données depuis notre serveur et penser également à limiter le nombre de lignes à afficher dans notre tableau « Datatable » afin d’optimiser le chargement de notre page.

Dans notre projet MVC de démo, nous allons garder notre exemple et en faire un modèle MVC qui nous servira tout au long des exemples à venir.

 

Le modèle Mvc métier

Nous créons donc, côté serveur, notre modèle « Browser » utilisé lors du premier article :

  public class BrowserModel
    {
        public string Engine { get; set; }
        public string Browser { get; set; }
        public string Platform { get; set; }
        public string Version { get; set; }
        public string Grade { get; set; }
    }
}

A partir de ce modèle, nous allons voir comment interagir avec notre plugin afin de l’alimenter côté client.

 

Le modèle du DataTables

Côté serveur, le DataTables Jquery possède également un modèle, permettant de gérer la majorité des scenarii (filtre, pagination, etc). Vous trouverez via le lien ci-dessous les informations relatives à ce modèle :

http://legacy.datatables.net/usage/server-side

Côté C#, voici un exemple de  modèle Mvc contenant quelques propriétés que nous jugeons utiles pour cette démo :

    /// <summary>
    /// Class that encapsulates most common parameters sent by DataTables plugin
    /// </summary>
    public class DataTableParamModel
    {
        /// <summary>
        /// Request sequence number sent by DataTable,
        /// same value must be returned in response
        /// </summary>
        public string sEcho { get; set; }

        /// <summary>
        /// Text used for filtering
        /// </summary>
        public string sSearch { get; set; }

        /// <summary>
        /// Number of records that should be shown in table
        /// </summary>
        public int iDisplayLength { get; set; }

        /// <summary>
        /// First record that should be shown(used for paging)
        /// </summary>
        public int iDisplayStart { get; set; }

        /// <summary>
        /// Number of columns in table
        /// </summary>
        public int iColumns { get; set; }

        /// <summary>
        /// Number of columns that are used in sorting
        /// </summary>
        public int iSortingCols { get; set; }

        /// <summary>
        /// Comma separated list of column names
        /// </summary>
        public string sColumns { get; set; }
    }

Nous verrons plus tard qu’il existe une quantité assez large de propriétés liées au Datatables Jquery.

 

Chargement asynchrone

Côté client

Côté client, nous allons encore une fois utiliser l’appel asynchrone intégré à la librairie afin de charger notre DataTables :

 $(document).ready(function () {

            var oTable = $('#exampleWithAjax');

            oTable.dataTable({
                "oLanguage": {
                    "sProcessing": "Traitement en cours...",
                    "sSearch": "Rechercher&nbsp;:",
                    "sLengthMenu": "Afficher _MENU_ &eacute;l&eacute;ments",
                    "sInfo": "Affichage de l'&eacute;lement _START_ &agrave; _END_ sur _TOTAL_ &eacute;l&eacute;ments",
                    "sInfoEmpty": "Affichage de l'&eacute;lement 0 &agrave; 0 sur 0 &eacute;l&eacute;ments",
                    "sInfoFiltered": "(filtr&eacute; de _MAX_ &eacute;l&eacute;ments au total)",
                    "sInfoPostFix": "",
                    "sLoadingRecords": "Chargement en cours...",
                    "sZeroRecords": "Aucun &eacute;l&eacute;ment &agrave; afficher",
                    "sEmptyTable": "Aucune donn&eacute;e disponible dans le tableau",
                    "oPaginate": {
                        "sFirst": "Premier&nbsp;&nbsp;",
                        "sPrevious": "Pr&eacute;c&eacute;dent&nbsp;&nbsp;",
                        "sNext": "Suivant",
                        "sLast": "&nbsp;&nbsp;Dernier"
                    },
                    "oAria": {
                        "sSortAscending": ": activer pour trier la colonne par ordre croissant",
                        "sSortDescending": ": activer pour trier la colonne par ordre d&eacute;croissant"
                    }
                },
                // activate Ajax call
                "bServerSide": true,
                // show loader
                "bProcessing": true,
                // Ajax call
                "sAjaxSource": "/Home/LoadBrowsers",
                "columns": [
                   { "title": "Engine" },
                   { "title": "Browser" },
                   { "title": "Platform" },
                   { "title": "Version", "class": "center" },
                   { "title": "Grade", "class": "center" }
                ]
            });
        });

Ici, on a spécifié que l’on souhaite charger les données depuis le serveur via la propriété : » bServerSide », et nous spécifions la méthode « serveur » à appeler : « sAjaxSource »: « /Home/LoadBrowsers ».

 

Fonctionnement

Une fois le Datatables instancié (ainsi qu’à l’instanciation également), un appel asynchrone sera émis vers le serveur afin de charger les données dans notre Tableau. Chaque événement observé engendrera également un appel vers le serveur afin de rafraîchir notre tableau en conséquence (par exemple lors d’une recherche, d’un tri, d’une pagination, etc).

Côté Serveur

Au niveau serveur (Controller MVC), voyons à quoi ressemble notre fonction de chargement du DataTables :

        [HttpGet]
        public JsonResult LoadBrowsers(DataTableParamModel param)
        {
            // Browser list
           var totalBrowserList = SrvBrowser.ListOfBrowsers();

           var filteredBrowserList = totalBrowserList.Skip(param.iDisplayStart).Take(param.iDisplayLength);

           var filteredResult = from b in filteredBrowserList
                           select new[] { b.Engine, b.Browser, b.Platform, b.Version, b.Grade };

            return Json(new
            {
                sEcho = param.sEcho,
                iTotalRecords = totalBrowserList.Count(),
                iTotalDisplayRecords = totalBrowserList.Count(),
                aaData = filteredResult
             },
              JsonRequestBehavior.AllowGet);
        }

Nous considérons ici que la liste d’éléments à afficher (les browsers) nous est fournie par un service tiers SrvBrowser (instance de ServiceBrowser (cf projet Git) ) via la méthode ListOfBrowsers.

Si nous observons le contenu de l’objet DataTableParamModel passé en paramètre, nous constatons qu’il contient bien les données du modèle associé sans que nous n’ayons eu à renseigner ces éléments côté client.

getDtatables

 Aperçu des valeurs passées en paramètre par le Datatables lors de l’appel Ajax

 Notre méthode retourne donc un objet Json contenant :

  • aaData : la liste des éléments à afficher par page
  • sEcho : le numéro de la page courante
  • iTotalRecords : le nombre total d’éléments à afficher
  • iTotalDisplayRecords : le nombre courant d’éléments à afficher par page
  • sSearch :  le mot clé du champs de recherche

A partir de ces propriétés, nous pouvons gérer notre chargement côté serveur, ainsi que la pagination et le filtre d’affichage de lignes prédéfinies. Cependant, dans cet exemple, nous n’effectuons aucun filtre de recherche ni de tri par colonne. Il faut également gérer ces fonctionnalités côté serveur. Voyons le code correspondant pour pallier à cela :

        [HttpGet]
        public JsonResult LoadBrowsersFull(DataTableParamModel param)
        {
            // Browser list
            var totalBrowserList = SrvBrowser.ListOfBrowsers();
            IEnumerable<BrowserModel> filteredBrowserList;

            // filter keyword search
            if (!string.IsNullOrEmpty(param.sSearch))
            {
                // limit search in column 1 and 2
                var isBrowserSearchable = Convert.ToBoolean(Request["bSearchable_1"]);
                var isEngineSearchable = Convert.ToBoolean(Request["bSearchable_0"]);

                filteredBrowserList = totalBrowserList.Where(bwsr =>
                                isBrowserSearchable && Convert.ToString(bwsr.Browser).Contains(param.sSearch.ToLower()) ||
                                isEngineSearchable && bwsr.Engine.ToLower().Contains(param.sSearch.ToLower()));
            }
            else
            {
                // No search filter
                filteredBrowserList = totalBrowserList;
            }

            var isBrowserPlatformSortable = Convert.ToBoolean(Request["bSortable_2"]);
            var sortColumnIndex = Convert.ToInt32(Request["iSortCol_0"]);
            Func<BrowserModel, string> orderingFunction = (bwsr =>
                                    sortColumnIndex == 2
                                    && isBrowserPlatformSortable ? Convert.ToString(bwsr.Platform) : "");

            var sortDirection = Request["sSortDir_0"];

            // asc or desc ofr column Platform
            filteredBrowserList = sortDirection == "asc"
                ? filteredBrowserList.OrderBy(orderingFunction)
                : filteredBrowserList.OrderByDescending(orderingFunction);

            var displayedFilteredBrowserList = filteredBrowserList.Skip(param.iDisplayStart).Take(param.iDisplayLength);

            var filteredResult = from b in displayedFilteredBrowserList
                                 select new[] { b.Engine, b.Browser, b.Platform, b.Version, b.Grade };

            return Json(new
            {
                sEcho = param.sEcho,
                iTotalRecords = totalBrowserList.Count(),
                iTotalDisplayRecords = totalBrowserList.Count(),
                aaData = filteredResult
            },
              JsonRequestBehavior.AllowGet);
        }

Au passage, nous constatons que nous pouvons récupérer d’autres champs du « DataTable Param » dans la « Request » comme par exemple les colonnes à filtrer, à trier, les indexes des colonnes, etc :

DataTable_Param

Aperçu des clés passées en paramètre par le DataTables

Bien que la liste des éléments paramétrables du « Datatables Jquery » soit longue et assez complète, nous pourrions avoir envie d’ajouter des filtres personnalisés : là encore le plugin est assez souple pour le permettre. Il suffira d’ajouter côté client les paramètres voulus via la propriété du Datatables « fnServerParams ». Imaginons un filtre global extérieur à notre Datatables, comme par exemple une liste de dates de création des navigateurs que nous ne souhaitons pas voir apparaître dans notre Tableau; cela nous donnera côté Js :

 // ---------------
'fnServerParams': function (aoData) {
                aoData.push({ 'name': 'bwsrCreatedDate', 'value': $('#bwsrCreatedDate').val() }
                );
            },
 // ---------------

Côté Serveur, il suffira de rajouter le paramètre en entrée de la méthode de filtre et d’en faire ce que nous souhaitons comme filtre :

 [HttpGet]
 public JsonResult LoadBrowsersFull(DataTableParamModel param, string bwsrCreatedDate)
 {

Optimisation Sql

Nous avons alléger le chargement de notre tableau en affichant un nombre limité d’enregistrements notamment via les filtres de lignes d’affichage et la pagination du Datatables. Mais imaginons des données provenant d’une table en Base de données contenant des millions de lignes… On pourra, dans ce cas, déléguer à une procédure stockée par exemple tout ou partie du filtre et chargement de notre Datatables. Les paramètres de filtre étant déjà passés en paramètre côté serveur, il nous suffira de les relayer à notre « proc stock » afin d’effectuer les filtres/tri/recherche par mot clé (avancée si besoin), etc
Voici à quoi pourrait ressembler notre requête SQL sous SQL SERVER :

CREATE PROCEDURE [dbo].[Browser_Search]
	@searchKey	varchar(256) = NULL,
	@skipRows int = 0,
    @takeRows int = 10,
    @count int = 0

AS

BEGIN
	SET NOCOUNT ON;

	DECLARE @TotalCount INT
	SELECT  @TotalCount = COUNT(BrowserId)
	FROM	TblBrowser

	SELECT *
	FROM
	(
		SELECT	ROW_NUMBER() OVER(ORDER BY BrowserId) AS NUMBERROW,
				Engine,
				Browser,
				Platform,
				Version,
				Grade,
				@TotalCount as TotalCount
		FROM TblBrowser
		WHERE
		   (
				@searchKey IS NULL
				OR
				(
						LOWER(Engine)	LIKE '%' +@searchKey + '%'
					OR  LOWER(Browser)	LIKE '%' +@searchKey + '%'
					OR  LOWER(Platform)	LIKE '%' +@searchKey + '%'
					OR  LOWER(Version)	LIKE '%' +@searchKey + '%'
					OR  LOWER(Grade)	LIKE '%' +@searchKey + '%'
				)
			)
		ORDER BY BrowserId DESC

	) AS TBL
	WHERE NUMBERROW BETWEEN (@skipRows + 1) AND (@skipRows + @takeRows)

END

Conclusion

Le « DataTables Jquery » est un plugin complet qui nous permet d’afficher nos données à exploiter sur le web sous forme de tableau. Il nous permet une certaine souplesse et beaucoup de facilités notamment avec la gestion native de filtres – tri – pagination – internationalisation – recherche par mot clé – appel asynchrone  etc. Il reste ainsi paramétrable, et « surchargeable » en terme de fonctionnalités.

Une fois pris en main, il peut s’avérer être un réel atout pour les développeurs web, en leur permettant de rendre disponible ou non tout ou partie d’un ensemble de fonctionnalités déjà embarquées.

En évitant de réinventer la roue, ce plugin vous fera gagner du temps sur bon nombre de fonctions d’affichage basique de données, où l’on s’attarderait communément.

 

Vous trouverez le code source de cet exemple sur mon git (ci-dessous).

github

A très bientôt !

 

Tags: asp.net mvc,

15 Commentaires Laisser un commentaire

Bonjour Damien,
Merci pour ce post. C’est exactement ce qu’il me fallait. Comme j’ai galéré avant de trouver ce blog.

Répondre

Bonjour.
Content pour vous.
N’hésitez pas à me contacter si vous avez des questions !
Bien à vous !

Répondre

J’ai une question… dans le cadre d’une exportation des données en CSV ou PDF, j’ai pu lire qu’il n’était pas possible (quand la dataTable est server-side) d’exporter toutes les données si elles sont paginée (vu que les boutons d’export, n’exporte que les données affichée)

Dans votre cas, comment gérer vous ça? (pour la création d’un fichier avec l’entier des données?)

Merci

Répondre

Bonjour,
Effectivement il existe un sous-plugin qui permet de faire des exports excel/pdf de votre DataTables. A ma connaissance il ne fait que l’export des lignes affichées.
2 solutions d’après moi :
– rajouter un fitre custom qui affiche toutes les lignes, et du coup, tu pourras exporter la totalité
– faire l’export mais en dehors du plugin DataTables, c’est à dire faire un appel ajax par exemple qui appelerait une méthode dédié qui export la totalité.

Répondre

Bravo et un grand merci pour vous, vos tutos sont excellent,
ce que je chercher depuis un peu de temps…..

Répondre

Merci à vous. N’hésitez pas si vous avez des intérogations !

Répondre

Bonjour Damien,
Merci pour votre tutoriel. Il est vraiment magnifique.
ça me permet de comprendre cet libraire au plus vite.

Répondre

Bonjour Nhat, content que ça vous aide. Cdlt, Georges

Répondre

Bonjour, sympa effectivement, j’utilisais jusqu’a present le Grid.mvc de codeplex
qui ressemble beaucoup à premiere vue…

Répondre

Bonjour Merci pour le tutoriel. j’aimerais avoir une orientation, existe-t’il des plugins javascript qui permettent de faire des tableaux d’objets editables et dynamiques (tel que je peux construire des pages ASP.NET MVC)???? genre un peu comme un mapping d’objet. du style dès que je double clique sur une ligne du tableau elle devient éditable est dès que je fini de l’éditer, l’élément modifié est directement mis à jour dans le tableau (ou list) d’objet.

j’aimerais pouvoir le faire avec des pages ASP.NET MVC.

Répondre

Hello,
Merci pour ton retour.
Tu peux utiliser ça par exemple : https://editor.datatables.net/examples/bubble-editing/inTableControls.html.
Sur le « DataTables », ce qui ce fait en général c’est l’édition de ligne (ou colonne) via une modal popup (par exemple celle de bootstrap qui marche très bien).
Du coup, tu ne perturbes pas la gestion d’affichage, de chargement, de pagination, etc du « DataTables ».
Si tu veux rendre éditable le tableau en lui même, ça t’oblige de gérer beaucoup plus de chose comme par exemple l’index de la ligne éditer, l’annulation du mode « edit », etc et surtout il faudra le faire manuellement.
A voir s’il existe des plugin qui te le font de façon automatique, mais je n’ai jamais creuser cette piste. ps : le plugin « DataTables » en lui même n’est pas si leger que ça, donc rajouter une autre librairie juste pour pouvoir éditer la ligne (donc modifier le dom au niveau de tableau) risque d’alourdir un peu plus la mécanique.

Répondre

Bonjour,

Tout d’abords, super explication, j’aurai gagné un temps fous si j’était tombé dessus plus rapidement lol.

J’essaye depuis se matin à introduire la dataTable dans mon projet Asp mais je rencontre plusieurs problèmes. Tout d’abords, je vois dans vos explications que la dataTable possède elle aussi un model. Est ce que vous l’avez rajouté vous même ou elle se crée automatiquement des le chargement du nuget ? Je ne l’ai pas dans mon projet.

Ensuite j’essaye d’afficher les données dans ma dataTable via un json (j’utilise JsonConvert.SerializeObject(Database.students());) qui converti une list d’object students en string. J’ai alors une erreur qui me dis : Requested unknown parameter ‘Name’ for row 0.

Quel est ce problème ? J’essaye de m’informer sur la doc officiel mais mon anglais n’est pas très … Avancé.

J’espère que vous allez pouvoir débloquer mon problème.

Merci d’avance !!

Répondre

Bonjour,
Pour le model (coté c#), il faut le rajouté à la main. Tu peux copier-coller la classe. Tu devrais la trouver également dans la documentation du DataTables. Ce model contient les propriétés correspondantes niveau JavaScript et le mapping est déjà fait, donc dans l’intellicense Visual Studio, tu veras qu’il reconnait ses propriétés lors d’appel asynchrone ou au chargement du DataTables.
Pour ton erreur, c’est difficile à dire sans plus d’infos, car je ne vois pas exactement ce que ramène « Database.Students(). Assure toi que ta conversion en objet json de ta liste de données s’effectue correctement. Par contre, ton message d’erreur semble venir d’un mauvais parametres; en tout cas, il ne semble pas reconnaitre ton parametre « Name ». ça peut venir d’un champ (proprieté) de la liste de « student » qui s’appelle « Name », et qui ne trouve pas son équivalent coté colonne du DataTables ==> vérifie donc que tu as les même noms de colonnes coté Js aussi au niveau de ton DAtaTAbles ==> attention à la casse ( tu as peut être un name ou lieu de Name). En esperant t’avoir éclairé.

Répondre

Ok super un grand merci. Enfaite j’essaye de rapatrier mes données via une methode ajax. Car pour le moment je parcours ma table avec un foreach directement dans ma vue (utilisations d’EF) mais je ne pense pas que c’est une bonne pratique. J’utilise donc l’objet JsonConvert.SerializeObject(student()); (student() est enfaite ma list qui correspond à ma table étudiant). J’ai encore un peux de mal avec la structure d’un Json, je ne sai donc pas trop comment le traiter dans les propriété de DataTables de ma méthode ajax. Je fesai comme ca, en sachant que je n’avais pas le modal de ma DataTable, c’est peux être juste ca qui fesai que ca ne fonctionnai pas.

$(‘#example’).DataTable({
« processing »: true,
« serverSide »: true,
« datatype »: « json »,
« ajax »: {
« url »: « test »,
« type »: « GET »
},
« aoColumnDefs »: [
{ « data »: « Name », « autoWidth »: true },
{ « data »: « Firstname », « autoWidth »: true },
{ « data »: « Age », « autoWidth »: true },
{ « data »: « Dob », « autoWidth »: true },
{ « data »: « Email », « autoWidth »: true }
]
});

Mon Json a ce type de format: {« data »: »[{\ »Name\ »:\ »Lucas\ »,\ »Firstname\ »:\ »Giunta\ »},{\ »Name\ »:\ »Bruno\ »,…….}] »}

Répondre

Bonjour,

Intégration du DataTables Jquery dans ASP.NET MVC 5 2e partie

j’ai une question concernant asp.net MVC 5 2ème partie, j’ai essayé de faire tourner le projet, mais je ne vois pas les méthodes qui attaquent la base de données. à quelle moment vous appellez la procédure stockée de recherche ? si vous avez le projet qui utilise la base de données, vous pouvez le poster en ligne pour voir comment ça interagit avec la BD(Model Vieuw Controler) car je suis nouveau en asp.net ?

Bien à vous
Eric

Répondre

Laisser un commentaire

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