IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Contribuez Discussion :

Rendre les tables HTML triables [Sources]


Sujet :

Contribuez

  1. #1
    Rédacteur

    Avatar de Bovino
    Homme Profil pro
    Développeur Web
    Inscrit en
    Juin 2008
    Messages
    23 647
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2008
    Messages : 23 647
    Points : 91 418
    Points
    91 418
    Billets dans le blog
    20
    Par défaut Rendre les tables HTML triables

    Dans le respect du Web sémantique, les tables HTML sont supposées contenir des données tabulaires. Or souvent, il peut être intéressant de vouloir organiser ces données en les triant.
    J'ai écrit une petite fonction JavaScript permettant de trier une table HTML dynamiquement.
    Cette fonction ne s'occupe pas de la structure réelle de la table, c'est à dire que cela fonctionne que vous ayez une table complète (tbody, thead, tfoot) ou non.
    Elle récupère les balises tr et en fonction de leur contenu (td ou th) rendent ces champs soit cliquables soit triables.
    L'utilisation est relativement simple : une fois la table disponible (c'est à dire ajoutée au DOM), vous pouvez appeler :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    new Triable(element, options);
    Les deux paramètres sont optionnels (mais si vous précisez les options, vous devez préciser aussi l'élément).
    element (par défaut, la première table rencontrée) correspond à la table.
    option est un objet avec pour l'instant 6 options possibles :
    • exclure : nom de classe (défaut aucune) > Empêcher de trier selon une colonne (toutes les données ne sont pas triables ). Sa valeur est un nom de classe à donner aux th non triables.
    • numstrict : booléen (vrai par défaut) > Les numériques peuvent ou non contenir d'autres caractères (devise par exemple) il faut savoir que le tri est typé pour permettre un tri cohérent avec les numériques.
    • classeTH : nom de classe (défaut aucune) > Correspond à la classe à donner au tr contenant les th cliquables. Vous pouvez avoir différentes lignes de th dans la table et souhaiter limiter les lignes cliquables.
    • classeNum : nom de classe (défaut numTri) > nom de classe à donner à un th pour forcer le tri numérique
    • classeCh : nom de classe (défaut txtTri) > nom de classe à donner à un th pour forcer le tri texte
    • classeDate : nom de classe (défaut dateTri) > nom de classe à donner à un th pour forcer le tri par date


    Par défaut, le format de date est automatiquement reconnu sous la forme [J]J/[M]M/[AA]AA. Le jour et le mois peuvent être sur 1 ou deux chiffres l'année sur 2 ou 4 chiffres (attention, la longueur de l'année doit être identique sur tous les champs pour ne pas perturber le tri : 09 n'est pas la même année que 2009 ). Donc si une table contient des données reconnues au format date et que le th correspondant ne force pas un type de tri, alors le tri sur l'ensemble de la colonne se fera par date.

    Voilà, c'est à peu près tout.
    Un exemple est en ligne.

    Voici le code :
    Code js : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    var Triable = function(elt, options){
    	// 	Options :
    	//		exclure : (chaine) nom de classe pour exclure des colonnes du tri ou pour empêcher une ligne th d'être cliquable (dans ce cas, c'est le comportement inverse de classeTH. Défaut : rien
    	//		numstrict : (booléen) les numériques peuvent contenir des caractères alpha (par exemple des unités) après les chiffres. Défaut : true
    	//		classeTH : (chaine) la classe des lignes th cliquables. Par défaut, ils le sont tous (sauf avec la classe eclure. !!! La classe s'applique au tr !!! Défaut : rien
    	//		classeNum : (chaine) nom de classe pour forcer un tri numérique. Défaut : numTri
    	//		classeCh : (chaine) nom de classe pour forcer un tri textuel. Défaut : txtTri
    	//		classeDate : (chaine) nom de classe pour forcer un tri par date (format : 'JJ/MM/AAAA'). Défaut : dateTri
    	this.elt = elt || document.getElementsByTagName('table')[0];
    	options = options || {};
    	this.exclure = options.exclure || false;
    	this.numstrict = options.numstrict || true;
    	this.classeTH = options.classeTH || '';
    	this.classeNum = options.classeNum || 'numTri';
    	this.classeCh = options.classeCh || 'txtTri';
    	this.classeDate = options.classeDate || 'dateTri';
    	this.base = this.elt.getElementsByTagName('tr');
    	this.separateur = '_';
    	this.getSeparateur();
    	var i = this.base.length, j;
    	this.en_cours = 0;
    	this.valeurs = [];
    	this.affichage = [];
    	this.typeTri = [];
    	var that, lavaleur, baseLigne;
    	while(i){
    		i--;
    		if(this.base[i].getElementsByTagName('th').length>0 && this.base[i].className.match(this.classeTH)){
    			baseLigne = this.base[i].getElementsByTagName('th');
    			j = baseLigne.length;
    			while(j){
    				j--;
    				if (baseLigne[j].className.match(this.exclure) || this.base[i].className.match(this.exclure)) {
    					continue;
    				}
    				if(!this.typeTri[j]){
    					this.typeTri[j] = baseLigne[j].className.match(this.classeCh) || baseLigne[j].className.match(this.classeNum) || '';
    				}
    				baseLigne[j].ref = j;
    				baseLigne[j].style.cursor = 'pointer';
    				that = this;
    				this.addEvent(baseLigne[j], 'click', function(e){
    					var origine = e.target?e.target:window.event.srcElement;
    					if (origine.ref == that.en_cours) {
    						that.retourne();
    					}
    					else {
    						that.multisort(origine.ref, origine.className);
    						that.en_cours = origine.ref;
    					}
    					that.affiche();
    				});
    			}
    		}
    		else if(this.base[i].getElementsByTagName('td').length>0){
    			j = this.base[i].getElementsByTagName('td').length;
    			var tabValeurs = [];
    			while(j){
    				j--;
    				if(!this.typeTri[j] && this.base[i].getElementsByTagName('td')[j].innerHTML.replace(/^[\s\n\t]+[.]+[\s\n\t]+$/g,'').match(/^(\d{1,2})\/(\d{1,2})\/(\d{2})(\d{2})?$/)){
    					this.typeTri[j] = this.classeDate;
    				}
    				tabValeurs.push(this.base[i].getElementsByTagName('td')[j].innerHTML.replace(/^[\s\n\t]+[.]+[\s\n\t]+$/g,''));
    			}
    			this.valeurs.push(tabValeurs.reverse().join(this.separateur));
    			this.affichage.push(i);
    		}
    	}
    	this.multisort(this.en_cours);
    	this.affiche();
    }
    Triable.prototype.addEvent = function(element, type, callback){
    	if (element.attachEvent){
    		element.attachEvent("on" + type, callback);
    	}
    	else{
    		element.addEventListener(type, callback, false);
    	}
    }
    Triable.prototype.gestClic = function(){
    	if(this.ref == that.en_cours){
    		that.retourne();
    	}
    	else{
    		that.multisort(this.ref);
    	}
    	that.affiche();
    }
    Triable.prototype.multisort = function(position){
    	var separateur = this.separateur;
    	switch (this.typeTri[position].toString()) {
    		case this.classeCh:
    			this.valeurs.sort(function(b, a){
    				a = a.split(separateur)[position].toLowerCase();
    				b = b.split(separateur)[position].toLowerCase();
    				return a == b ? 0 : a < b ? -1 : 1;
    			});
    			break;
    		case this.classeNum:
    			this.valeurs.sort(function(b, a){
    				a = parseFloat(a.split(separateur)[position].replace(/[^\d\.]*/g, '')) || 0;
    				b = parseFloat(b.split(separateur)[position].replace(/[^\d\.]*/g, '')) || 0;
    				return a == b ? 0 : a < b ? -1 : 1;
    			});
    			break;
    		case this.classeDate:
    			this.valeurs.sort(function(b, a){
                    a = new Date(parseInt(a.split('/')[2],10), parseInt(a.split('/')[1],10) - 1, parseInt(a.split('/')[0],10));
                    b = new Date(parseInt(b.split('/')[2],10), parseInt(b.split('/')[1],10) - 1, parseInt(b.split('/')[0],10));
                    return a == b ? 0 : a < b ? -1 : 1;
                });
                break;
    		default:
    			this.valeurs.sort(function(b, a){
    				a = a.split(separateur)[position].toLowerCase();
    				b = b.split(separateur)[position].toLowerCase();
    				if (this.numstrict) {
    					a = (parseFloat(a) == a) ? parseFloat(a) : a;
    					b = (parseFloat(b) == b) ? parseFloat(b) : b;
    				}
    				else 
    					if (!isNaN(parseFloat(a)) && !isNaN(parseFloat(b))) {
    						a = parseFloat(a);
    						b = parseFloat(b);
    					}
    				if (a === b) {
    					return 0;
    				}
    				if (typeof a === typeof b) {
    					return a < b ? -1 : 1;
    				}
    				return typeof a < typeof b ? -1 : 1;
    			});
    	}
    }
    Triable.prototype.retourne = function(){
    	this.valeurs.reverse();
    }
    Triable.prototype.affiche = function(){
    	for(var i=0; i<this.affichage.length; i++){
    		for(var j=0; j<this.base[this.affichage[i]].getElementsByTagName('td').length; j++){
    			this.base[this.affichage[i]].getElementsByTagName('td')[j].innerHTML = this.valeurs[i].split(this.separateur)[j];
    		}
    	}
    }
    Triable.prototype.getSeparateur = function(){
    	var lesElements = this.elt.getElementsByTagName('td');
    	var nbElements = lesElements.length;
    	while(nbElements){
    		nbElements--;
    		while(lesElements[nbElements].innerHTML.match(this.separateur)){
    			this.separateur += '_';
    		}
    	}
    }
    Exemples d'appels :
    Code html : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    <body onload="new Triable()">
    <body onload="new Triable(document.getElementById('matable'))">
    <body onload="new Triable(document.getElementById('matable'), {exclure:'no_sort',numstrict:true,classeTH:'sortable'})"

    EDIT
    Améliorations envisagées :
    * Ajouter un style CSS pour indiquer quelle colonne est triée et dans quel sens.
    Pas de question technique par MP !
    Tout le monde peut participer à developpez.com, vous avez une idée, contactez-moi !
    Mes formations video2brain : La formation complète sur JavaScriptJavaScript et le DOM par la pratiquePHP 5 et MySQL : les fondamentaux
    Mon livre sur jQuery
    Module Firefox / Chrome d'intégration de JSFiddle et CodePen sur le forum

  2. #2
    Expert confirmé
    Avatar de le_chomeur
    Profil pro
    Développeur informatique
    Inscrit en
    Février 2006
    Messages
    3 653
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Février 2006
    Messages : 3 653
    Points : 4 835
    Points
    4 835
    Par défaut
    Nickel bovino exactement ce dont je cherchais ^^
    est ton ami fait gagner du temps à ceux qui aident , donc un message avec la balise résolu laisse plus de temps pour résoudre d'autres problèmes

    Premier ministre du CCMPTP (Comité Contre le Mot "Problème" dans les Titres de Posts )

  3. #3
    Rédacteur

    Avatar de Bovino
    Homme Profil pro
    Développeur Web
    Inscrit en
    Juin 2008
    Messages
    23 647
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2008
    Messages : 23 647
    Points : 91 418
    Points
    91 418
    Billets dans le blog
    20
    Par défaut
    Ah ben ça tombe bien

    Je viens de faire quelques améliorations :
    * Le tri se fait en concaténant les valeurs de chaque ligne avec un séparateur. J' ai donc ajouté la gestion des cas où ce séparateur soit présent dans la valeur d'une des cellule.
    * La classe exclure peut désormais s'appliquer à un tr de th, pour permettre de ne pas la rendre triable sans avoir à appliquer une classe à tous les autres.
    Pas de question technique par MP !
    Tout le monde peut participer à developpez.com, vous avez une idée, contactez-moi !
    Mes formations video2brain : La formation complète sur JavaScriptJavaScript et le DOM par la pratiquePHP 5 et MySQL : les fondamentaux
    Mon livre sur jQuery
    Module Firefox / Chrome d'intégration de JSFiddle et CodePen sur le forum

  4. #4
    Expert confirmé
    Avatar de le_chomeur
    Profil pro
    Développeur informatique
    Inscrit en
    Février 2006
    Messages
    3 653
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Février 2006
    Messages : 3 653
    Points : 4 835
    Points
    4 835
    Par défaut
    je vais devoir le modifier pour :

    - faire concorder une entete avec une colonne d'un autre tableau xD
    est ton ami fait gagner du temps à ceux qui aident , donc un message avec la balise résolu laisse plus de temps pour résoudre d'autres problèmes

    Premier ministre du CCMPTP (Comité Contre le Mot "Problème" dans les Titres de Posts )

  5. #5
    Rédacteur

    Avatar de Bovino
    Homme Profil pro
    Développeur Web
    Inscrit en
    Juin 2008
    Messages
    23 647
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2008
    Messages : 23 647
    Points : 91 418
    Points
    91 418
    Billets dans le blog
    20
    Par défaut
    J'ai ajouté le tri par date (détection automatique ou forcé).
    Pas de question technique par MP !
    Tout le monde peut participer à developpez.com, vous avez une idée, contactez-moi !
    Mes formations video2brain : La formation complète sur JavaScriptJavaScript et le DOM par la pratiquePHP 5 et MySQL : les fondamentaux
    Mon livre sur jQuery
    Module Firefox / Chrome d'intégration de JSFiddle et CodePen sur le forum

  6. #6
    Candidat au Club
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    5
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 5
    Points : 3
    Points
    3
    Par défaut Super
    Merci beaucoup,

    voila un script bien utile, bien pratique et pas en mode usine à gaz!!!


  7. #7
    Candidat au Club
    Homme Profil pro
    Inscrit en
    Avril 2011
    Messages
    3
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2011
    Messages : 3
    Points : 3
    Points
    3
    Par défaut
    Franchement au top
    Au début j'avais des soucis sur le tri de quelques colonnes mais c'était du au fait que j'avais 2 tr avec des colspan/rowspan (meilleure mise en page), une fois avoir tout réécris sur un seul tr ça marchait sauf pour les dates.

    Je comprenais pas car sur ta page test ça marchait donc j'ai donc regardé d'où ça pouvait venir et en fait pour le cas du "classeDate" tu as oublié de spliter sur le séparateur avant de spliter sur le "/".
    Dans ton cas, si la colonne date n'était pas la première du tableau, le split correspondant au jour avait aussi tous les champs des précédentes colonnes.
    J'ai aussi rajouter un ptit test pour le cas où ma date était nulle (champs vide).

    Voila
    Et merci encore

  8. #8
    Nouveau membre du Club
    Inscrit en
    Août 2006
    Messages
    45
    Détails du profil
    Informations forums :
    Inscription : Août 2006
    Messages : 45
    Points : 32
    Points
    32
    Par défaut
    Ton script est excellent de simplicité, presque parfait

    J'émets une suggestion : admettons qu'on ait une colonne 1 avec un compteur de ligne et que cette colonne ne doive pas bouger malgré les tris.
    Comment faire ?

  9. #9
    Rédacteur

    Avatar de Bovino
    Homme Profil pro
    Développeur Web
    Inscrit en
    Juin 2008
    Messages
    23 647
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2008
    Messages : 23 647
    Points : 91 418
    Points
    91 418
    Billets dans le blog
    20
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    // 	Options :
    //		exclure : (chaine) nom de classe pour exclure des colonnes du tri ou pour empêcher une ligne th d'être cliquable (dans ce cas, c'est le comportement inverse de classeTH. Défaut : rien
    Pas de question technique par MP !
    Tout le monde peut participer à developpez.com, vous avez une idée, contactez-moi !
    Mes formations video2brain : La formation complète sur JavaScriptJavaScript et le DOM par la pratiquePHP 5 et MySQL : les fondamentaux
    Mon livre sur jQuery
    Module Firefox / Chrome d'intégration de JSFiddle et CodePen sur le forum

  10. #10
    Membre du Club
    Homme Profil pro
    Technicien maintenance
    Inscrit en
    Février 2015
    Messages
    79
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 28
    Localisation : France, Doubs (Franche Comté)

    Informations professionnelles :
    Activité : Technicien maintenance
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Février 2015
    Messages : 79
    Points : 48
    Points
    48
    Par défaut Question
    Merci beaucoup cela m'a aidé

    J'ai juste une petite question : si mes dates sont toutes sous le format non pas JJ-MM-AAAA comme les tiennes mais sous le format AAA-MM-JJ, le tri fonctionnera-t-il quand même ?

    Merci et bonne journée.

  11. #11
    Modérateur

    Avatar de NoSmoking
    Homme Profil pro
    Inscrit en
    Janvier 2011
    Messages
    16 957
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Janvier 2011
    Messages : 16 957
    Points : 44 119
    Points
    44 119
    Par défaut
    Bonjour,
    Citation Envoyé par Bovino
    J'ai ajouté le tri par date (détection automatique ou forcé).
    ...tes essais ont donnés quoi ?

  12. #12
    Membre du Club
    Homme Profil pro
    Technicien maintenance
    Inscrit en
    Février 2015
    Messages
    79
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 28
    Localisation : France, Doubs (Franche Comté)

    Informations professionnelles :
    Activité : Technicien maintenance
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Février 2015
    Messages : 79
    Points : 48
    Points
    48
    Par défaut
    Salut je sais pas si c'est a moi que tu as posé la question mais je rien n'a marché pour moi donc j'ai utilisé une bibliothèque jQuery bien plus pratique bref bonne soirée a+

  13. #13
    Membre à l'essai
    Profil pro
    Inscrit en
    Février 2010
    Messages
    11
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Février 2010
    Messages : 11
    Points : 15
    Points
    15
    Par défaut
    Citation Envoyé par Stephh77 Voir le message
    Franchement au top
    Au début j'avais des soucis sur le tri de quelques colonnes mais c'était du au fait que j'avais 2 tr avec des colspan/rowspan (meilleure mise en page), une fois avoir tout réécris sur un seul tr ça marchait sauf pour les dates.

    Je comprenais pas car sur ta page test ça marchait donc j'ai donc regardé d'où ça pouvait venir et en fait pour le cas du "classeDate" tu as oublié de spliter sur le séparateur avant de spliter sur le "/".
    Dans ton cas, si la colonne date n'était pas la première du tableau, le split correspondant au jour avait aussi tous les champs des précédentes colonnes.
    J'ai aussi rajouter un ptit test pour le cas où ma date était nulle (champs vide).

    Voila
    Et merci encore
    6 ans après... Stephh77 est toujours actif sur ce forum ?
    Merci pour cette contribution, je comprends ce que vous expliquez avec les champs date mais mes connaissances (nulles) en javascript ne me permettent pas de corriger le script pour l'utiliser.
    C'est dommage car c'est juste ce que je cherchais ;-)
    V.

  14. #14
    Invité
    Invité(e)
    Par défaut
    @softopus


  15. #15
    Membre à l'essai
    Profil pro
    Inscrit en
    Février 2010
    Messages
    11
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Février 2010
    Messages : 11
    Points : 15
    Points
    15
    Par défaut
    Oui, ce qu'on trouve sur ce site est un réel couteau suisse mais ce que j'aimais dans le code que j'ai trouvé dans ce post, c'est qu'il fait 150 lignes et qu'un jour, peut-être, j'aurais compris comment le script fonctionnait (plutôt que de faire un stupide copier-coller). :-)

Discussions similaires

  1. rendre les cellules de ma table editable
    Par christianf dans le forum AWT/Swing
    Réponses: 10
    Dernier message: 29/09/2007, 07h22
  2. Réponses: 2
    Dernier message: 13/12/2006, 17h09

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo