Partage

[jQuery] Exercice pour s'entraîner

Listes déroulantes liées

Sujet résolu
16 novembre 2011 à 11:17:12

Bonjour à tous,

Je vous propose aujourd'hui un exercice sur jQuery, dans l'idée de faire progresser les membres mais aussi d'animer la section. ;)

Avant d'entrer dans le vif du sujet, il y aura un certain nombre de règles à respecter pour que tout se passe bien dans ce topic.

Règles


  1. Le troll et le flood ne sont pas tolérés. Inutile de balancer des "Pourquoi jQuery et pas Mootools ?", les messages non constructifs seront modérés.
  2. Je vous fournis le code HTML, vous n'aurez pas le droit de le modifier.
  3. Votre réponse contiendra uniquement du code jQuery avec la balise <secret> de manière à respecter ceux qui n'ont pas commencé l'exercice.
  4. Evidemment, le code que vous posterez devra être de vous, pas la peine de recopier un code externe, cela n'a pas d'intérêt. L'utilisation de plugins n'est pas nécessaire.


Objectif du script


Description


Nous avons 2 listes déroulantes, la première (liste A) contient des fruits et la seconde (liste B) est notre panier. Il faudra donc remplir notre panier de fruits.
Pour ce faire, 2 boutons sont à notre disposition : "Ajouter" permet de prendre un fruit de la liste A et de l'insérer dans la liste B (tout en le supprimant de la liste A).
Le bouton "Supprimer" fait exactement la même chose dans le sens inverse.
Dans votre code, n'oubliez pas de prendre en considération l'état de ces 2 boutons : ils ne doivent pas être cliquables si aucun élément de leur liste respective n'est sélectionné.

Le but n'est pas de faire le code le plus court possible. Essayez en revanche de l'optimiser, par exemple : éviter la répétition du $ de jQuery au profit de variables, si un traitement doit être fait plus d'une fois, alors utilisez une fonction...

HTML


Je vous donne le code minimal fonctionnel. Ne paniquez pas, le code n'est pas valide et j'utilise un tableau pour la mise en forme, ceci n'est pas le coeur du débat. :-°
<table>
	<tr>
		<td>Liste des fruits :<br />
			<select id="liste_fruits" size="8" style="width:90px;">
				<option value="ananas">Ananas</option>
				<option value="banane">Banane</option>
				<option value="citron">Citron</option>
				<option value="fraise">Fraise</option>
				<option value="orange">Orange</option>
				<option value="pomme">Pomme</option>
				<option value="raisin">Raisin</option>
			</select>
		</td>
		<td>
			<button id="ajouter" disabled="disabled">Ajouter</button><br />
			<button id="supprimer" disabled="disabled">Supprimer</button>
		</td>
		<td>Mon panier :<br />
			<select id="panier" size="8" style="width:90px;">
			</select>
		</td>
	</tr>
</table>


Rendu


Image utilisateur


Ressources




Bon code ! :pirate:

Il n'y a pas une seule solution, je donnerai plus tard ma version du script commentée, j'attends un peu pour ne pas vous inciter à la regarder. :)
16 novembre 2011 à 14:48:03

juste pour le plaisir. C'est assez simpliste... tout est basé sur de l'écoute d'event !!!


$(document).ready(function(){
	$('#liste_fruits').click(function(){
		list = $('#liste_fruits').html();
		if (list != ''){
			$('#ajouter').removeAttr('disabled');
			$('#supprimer').attr('disabled','disabled');
		}
	});
	$('#panier').click(function(){
		list = $('#panier').html();
		if (list != ''){
			$('#supprimer').removeAttr('disabled');
			$('#ajouter').attr('disabled','disabled');
		}
	});
	$('#ajouter').click(function(){
		addFruits($('#liste_fruits option:selected').val(),$('#liste_fruits option:selected').text());
	});
	$('#supprimer').click(function(){
		rmFruits($('#panier option:selected').val(),$('#panier option:selected').text());
	});
	$('#panier').html('');
});

function addFruits(fruits,Fruits) {
	save_fruits = '<option value="'+fruits+'">'+Fruits+'</option>';
	list = $('#liste_fruits').html();
	var regList=new RegExp(save_fruits,'g');
	list = list.replace(regList,'');
	$('#liste_fruits').html(list);
	$('#panier').html($('#panier').html()+save_fruits);
	$('#liste_fruits').html(list);
	$('#ajouter').attr('disabled','disabled');
}

function rmFruits(fruits,Fruits) {
	save_fruits = '<option value="'+fruits+'">'+Fruits+'</option>';
	list = $('#panier').html();
	var regList=new RegExp(save_fruits,'g');
	list = list.replace(regList,'');
	$('#panier').html(list);
	$('#liste_fruits').html($('#liste_fruits').html()+save_fruits);
	$('#panier').html(list);
	$('#supprimer').attr('disabled','disabled');
}


Citation : Desolation


Votre réponse contiendra uniquement du code jQuery


Je l'ai pris a la lettre : je n'ai donc pas commenté mon code :D

Si besoin je le ferais suffit de demander
Never Trust User Input This is the truth
16 novembre 2011 à 15:14:04

Salut, voici un code un peu différent avec le minimum de $ et le maximum de factorisation du code. Et un petit plus pour la selection multiple:

<html>
<head>
 <script type="text/javascript" src="javascript/jquery.js"></script>
 <script type="text/javascript">
 		$(document).ready(function(){
 			var ajouter = $("#ajouter");
 			var supprimer = $("#supprimer");
 			var listeFruits = $("#liste_fruits");
 			var panier = $("#panier");
 			
 			bindChangeSelect(listeFruits, ajouter);
 			bindChangeSelect(panier, supprimer);
 		
 			initDeplacerFruit(ajouter, listeFruits, panier);
 			initDeplacerFruit(supprimer, panier, listeFruits);
 		});
 		
 		
 		function bindChangeSelect(selectElem, buttonModify){
 			if(selectElem.val() != null && selectElem.val().length > 0){
 				buttonModify.removeAttr("disabled");
 			}
 			selectElem.bind("change", function(){
 				if($(this).val().length > 0){
 					buttonModify.removeAttr("disabled");
 				}else{
 					buttonModify.attr("disabled","disabled");
 				}
 			});
 		}
 		function initDeplacerFruit(buttonClick, selectSrc, selectDest){
 			buttonClick.click(function(){
	 			$(selectSrc+"option:selected").each(function(){
	 				$(this).removeAttr("selected");
	 				$(this).appendTo(selectDest);			
	 				buttonClick.attr("disabled","disabled");
	 			});
	 		});
 		}
 </script>
</head>
<body>
<table>
	<tr>
		<td>Liste des fruits :<br />
			<select id="liste_fruits" size="8" style="width:90px;" multiple="multiple" >
				<option value="ananas">Ananas</option>
				<option value="banane">Banane</option>
				<option value="citron">Citron</option>
				<option value="fraise">Fraise</option>
				<option value="orange">Orange</option>
				<option value="pomme">Pomme</option>
				<option value="raisin">Raisin</option>
			</select>
		</td>
		<td>
			<button id="ajouter" disabled="disabled">Ajouter</button><br />
			<button id="supprimer" disabled="disabled">Supprimer</button>
		</td>
		<td>Mon panier :<br />
			<select id="panier" size="8" style="width:90px;">
			</select>
		</td>
	</tr>
</table>
</body>
</html>



@Desolation : si tu peut emettre quelques critiques sur les différents code, histoire de tirer le meilleur partie de toutes les réponse.

Bon codage a tous.
16 novembre 2011 à 16:02:40

Tout d'abord merci à vous d'avoir fait cet exercice, je trouve cela très enrichissant de voir que pour un sujet on a tous une méthode particulière. :)

Concernant mes remarques :

hani_1 : si je mets de côté l'utilisation massive du $, je trouve que tu t'es compliqué la tâche. En effet tes 2 fonctions font grossièrement le même traitement. Il y avait une optimisation à faire de côté-là. ;)
Je n'ai pas compris pourquoi tu es parti sur RegExp.

ninlock : tu as été plus méthodique en lançant tes fonctions. As-tu testé ton code ? Je reste perplexe quant à la ligne 33. Parce que selectScr contient un objet jQuery, que tu concatènes avec "option:selected", cela ne doit en théorie pas fonctionner ? Me trompe-je ?

Je vous montrerai mon code plus tard car j'aimerais d'autres propositions. Mais j'ai vraiment l'impression que vous ayez fait plus compliqué que moi. :)
16 novembre 2011 à 16:14:09

Si, c'est valide comme sélecteur, et oui je l'ai testé, d’ailleurs il te suffit de faire un copier/coller dans une page blanche et de lancer avec ton navigateur.
En fait jQuery à mis en place des fonctions qui permette de passer plusieurs type d'argument, (évidemment me dira tu c'est la force du javascript, ou sa faiblesse, cela dépend des avis).
Une fois qu'il reçoit un argument il vérifie le type de ce dernier afin de savoir quel processus il doit engager, du coup on constate parfaitement ce comportement avec par exemple $("#monElement") ou $(this) où ce dernier n'est pas une String mais bien un élément jQuery. Du coup dans mon cas je suppose que le selectScr + "..." représente en fait selectScr.toString()+"..." où selectScr.toString doit être un identifiant unique créé par jquery.
Voilà, le code est peut être un petit peu plus chargé car j'ai bien tous séparé afin d'être clair en ajoutant la gestion de la selection multiple.
16 novembre 2011 à 16:20:51

J'avais simplement commencé avec un array global et des regexp pour garder les fruits classé dans le même ordre. Puis j'ai vu que ce n'était pas requis donc j'ai supprimé pas mal ligne. les regexp fonctionnait quand même donc je les ai laissé !!! D'ou les regexp.


Pour les deux fonctions je suis d'accord avec un array de param (5 clef) j'aurais pu en faire une seule.


Je constate que tu tiens vraiment a ce qu'on utilise peu le $ ?
C'est juste une lubie ou il y a une recherche de performance ?
C'est une réponse qui m'intéresse fortement ça :D

Never Trust User Input This is the truth
16 novembre 2011 à 16:26:43

Personnellement je pense qu'il y a un gain de performance car en appelant $, jQuery lance un processus complexe, alors que si tu créé une variable qui stock l'objet jquery, tu créé simplement une référence de l'objet en mémoire, donc plus d'appel d'instruction complexe, afin si, une par élément.
D'ailleurs pour t'en rendre conte, utilise $ 2 fois et passe en mode débug sur le fichier jquery et avance pas a pas tu constatera la quantité d'instruction exécuté.
Ensuite tu l'utilise une fois en l'assignant a une variable et tu réutilise cette variable, dans ce cas tu constate qu'il ne passe qu'une seule fois dans le script jQuery.
16 novembre 2011 à 16:27:35

ninlock : chez moi ça marche pas ou alors je le fais mal.
var $liste_fruits = $('#liste_fruits');
alert($($liste_fruits+' option:selected').val());

Me rend uncaught exception: Syntax error, unrecognized expression: [object Object] (1.6.4)

hani_1 : ok pour le tri ! :) Oui pour le $ il y a une histoire de performance (j'ai du mal à remettre la main sur des articles traitant ce sujet).

16 novembre 2011 à 16:31:59

@Desolation : son code marche chez moi (jquery-1.5.1.min.js)

Je vais chercher les article qui en traite si je les trouve je posterais les liens

@ninlock : Je vais faire quelques test pour voir

Merci
Never Trust User Input This is the truth
16 novembre 2011 à 16:42:41

Ah oui par contre pour mon code il faut peut être changer la source du script jQuery (actuellement src="javascript/jquery.js", il suffit de pointer vers un chemin ou la librairie existe), je suis en version 1.6.4
16 novembre 2011 à 16:52:01

Voila mon code :)

<script type="text/javascript">
$(function(){
    
    $('#ajouter,#supprimer').click(function(){        
        var t= $(this);
        var action =($(this).attr('id')=='ajouter') ? {'toEnableId':'supprimer','ajout':true} : {'toEnableId':'ajouter','ajout':false};
        move(action.ajout);
        t.attr('disabled','true');
        $('#'+action.toEnableId).removeAttr('disabled');
    });
            
    $('#liste_fruits option').live('click',function(){
        $('#ajouter').removeAttr('disabled');        
    });
    
    $('#panier option').live('click',function(){
        $('#supprimer').removeAttr('disabled');        
    });
    
});

function move(ajout){    
    var action =(ajout) ?  {'btn':'ajouter','from':'liste_fruits','to':'panier'} :  {'btn':'supprimer','from':'panier','to':'liste_fruits'};            
    var selected = $('#'+action.from+' option:selected');
    $('#'+action.to).append(selected);                                    
    if(!$('#'+action.from+' option').length){
                $('#'+action.btn).attr('disabled','true');    
    }                
}
</script>

16 novembre 2011 à 17:28:43

noaman00 : c'est très spécial mais pourquoi pas ! Merci. :)
Cependant tu n'as pas respecté les règles.

Citation

Votre réponse contiendra uniquement du code jQuery avec la balise <secret> de manière à respecter ceux qui n'ont pas commencé l'exercice.



ninlock : tu as testé mon code d'exemple qui tient une erreur ?
16 novembre 2011 à 17:40:14

Ah non c'est quoi qu 'il faut tester? ça ?
var $liste_fruits = $('#liste_fruits');
alert($($liste_fruits+' option:selected').val());

où est-il ecrit? Dans le $(document).ready?

De plus concidère plutôt les $ comme mot clé jQuery du coup test plutôt :
var liste_fruits = $('#liste_fruits');
alert($(liste_fruits+' option:selected').val());

De plus il faut le mettre dans le ready sinon l'élément du DOM n'est pas encore construit.

Et il faut savoir que $(liste_fruits+' option:selected') est null au début, d'où le if(selectElem.val() != null && selectElem.val().length > 0){ buttonModify.removeAttr("disabled"); } dans la fonction bindChangeSelect
16 novembre 2011 à 17:57:16

Oui ce code est dans le ready. Après le $ devant la variable c'est pour montrer que c'est un selecteur, le retirer ne change rien.

Ceci est un exemple pour te montrer que je comprends pas comment ton code peut fonctionner car tu as fait la même chose, un truc m'echappe...
16 novembre 2011 à 18:17:30

Je vient de mettre ton code dans ma page et l'alert me retourne undefined, mais c'est normal car $($liste_fruits+' option:selected') retourne un tableau d'options sélectionnées et non pas une seule option sélectionnée.

Et pour le $, je sais que cela change rien, c'était juste pour dire qu'il est plus clair de garder cette notation pour les appel jQuery, mais après cette remarque n'as que peu d'importance.
16 novembre 2011 à 19:08:30

noaman00 : j'avais pas vu mais tu es invité à éditer ton message afin qu'il respecte les règles du topic stp. :)

ninlock : j'ai trouvé une solution toute bête, il suffit d'utiliser le préfixe .selector !

Exemple :

var test = $('#test').selector;
alert(test); // renvoie #test


J'en profite pour mettre ma version du script (version en ligne) :


$(document).ready(function() {
	// variables sélécteur
	var $liste_fruits = $('#liste_fruits');
	var $panier = $('#panier');
	var $ajouter = $('#ajouter');
	var $supprimer = $('#supprimer');
	
	// on sélectionne un fruit dans la liste
	$liste_fruits.change(function() {
		$ajouter.attr('disabled', false);
	});
	
	// on sélectionne un fruit dans le panier
	$panier.change(function() {
		$supprimer.attr('disabled', false);
	});
	
	$ajouter.click(function() {
		$ajouter.attr('disabled', true); // on désactive le bouton
		transfertFruit($($liste_fruits.selector +' option:selected'), $panier);
	});
	
	$supprimer.click(function() {
		$supprimer.attr('disabled', true); // on désactive le bouton
		transfertFruit($($panier.selector +' option:selected'), $liste_fruits);
	});
});
 
// fonction qui va s'occuper de basculer un fruit d'une liste à l'autre
function transfertFruit($fruit, $panierArrivee) {
	// on ajoute l'option au panier
	$('<option>', {
		value: $fruit.val(),
		text: $fruit.text()
	}).appendTo($panierArrivee);
	
	$fruit.remove(); // on supprime le fruit de la liste de départ
}


J'accepte tous vos commentaires. ;)
16 novembre 2011 à 19:22:47

Tu trouve pas plus pratique de juste faire avec le each $(this).appendTo(selectDest)?
16 novembre 2011 à 19:30:40

ninlock : oui pourquoi pas, toutes les manières aboutissent au même résultat. ;)

noaman00 : merci. :)

Si ce sujet vous a plu je pourrai réitérer avec un deuxième exercice.
16 novembre 2011 à 20:32:32

Très bien comme sujet, cependant il me semblerait intéressant de conclure à certaines bonnes pratiques afin de savoir comment optimiser un code et le rendre le plus évolutif possible.
Je vais essayer de faire différents tests avec ces différents codes, et je ferait un retour si cela me semble pertinent.
16 novembre 2011 à 20:46:13

Pour les bonnes pratiques on les a plus ou moins citées. Il n'y a pas vraiment de conclusion, comme j'ai dit il y a un tas de manière de résoudre cet énoncé.

Apparemment hani_1 s'est perdu sur la toile en voulant chercher les articles. :)
17 novembre 2011 à 14:16:52

J'ai pas trouvé grand chose qui soit concluant.

Cet article apporte des element de réponse. Mais en approfondissant un peu je me rend compte que ce qui est préconisé c'est d'utiliser le JQuery une fois qu'on lui a maché le travail avec du JS pur et dur !!!

De plus cet article date de 2008. donc je doute qu'il soit encore fiable aujourd'hui alors que le systeme de selecteur jquery a été repensé depuis!!!

Never Trust User Input This is the truth
17 novembre 2011 à 15:42:58

Effectivement j'ai lu l'article, c'est intéressant mais ne doit plus être à l'ordre du jour.
17 novembre 2011 à 19:17:36

@hani_1 : Je suis tombé sur un petit blog qui me parait contenir de bonne remarque concernant ce que j'avais dit précédemment pour la répétition des $. Il explique succinctement pour quoi il est toujours mieux déclaré une variable plutôt que de réutiliser le selecteur $, avec quelques autres bonne pratiques:
http://blog.arnaud-k.fr/2009/10/26/5-c [...] -avec-jquery/
17 novembre 2011 à 19:27:30

Merci ninlock c'est celui-ci que j'avais déjà lu. ;)

Vous seriez OK pour un autre exercice ?
17 novembre 2011 à 20:28:53

Entièrement d'accord. Je trouve cela très intéressant ce type d'exercice.
6 janvier 2012 à 15:57:31

Bonjour, j'arrive un peu tard ...
mais ça m'intéresse tellement que je me permet de déterrer cet intéressant exercice :D

voici ce que j'ai fait :

function move($dest, $selected){
     $dest.append('<option value="'+$selected.val()+'" >'+$selected.text()+'</option>');
        $selected.remove();   
}

$(document).ready(function() {
    var $lst = $('#liste_fruits');
    var $panier = $('#panier');
    var $add = $('#ajouter');
    var $delete = $('#supprimer');
    
    
    $lst.change(function(){
        $add.attr('disabled', false);
    });
    $panier.change(function(){
        $delete.attr('disabled', false);
     });
    $add.click(function(){
        move($panier, $('#liste_fruits option:selected'));
        $add.attr('disabled', true);
    });
    $delete.click(function(){
        move($lst, $('#panier option:selected'));
        $delete.attr('disabled', true);
    });
});


je l'ai aussi mis en ligne ici (génial ce site ! [cf signature de Desolation])

Citation : Desolation

Vous seriez OK pour un autre exercice ?



Je ne demande pas mieux, j'adore ça.
Seulement je ne suis pas souvent sur les forums js, alors je risque de ne pas les voir.
merci.

NB

une suite intéressant pour cet exercice, ce serait de permettre le choix multiple ;)
et par exemple d'ajouter ou de supprimer quand ou double clic sur une ligne, ou encore quand on fait entrée ...


EDIT


Voici une version améliorée.
J'ai juste rajouté un attribut "multiple" sur chaque select.
On peu sélectionner plusieurs item, ils sont tous ajoutés quand on clic su le bouton, et aussi quand on fait entrée.

var $lst = $('#liste_fruits');
    var $panier = $('#panier');
    var $add = $('#ajouter');
    var $delete = $('#supprimer');

function move($dest, $selected){
     $dest.append('<option value="'+$selected.val()+'" >'+$selected.text()+'</option>');
        $selected.remove();   
}
function add(){
   $('#liste_fruits option:selected').each(function(){
            move($panier, $(this));
     });
   $add.attr('disabled', true); 
}

function remove(){
     $('#panier option:selected').each(function(){
            move($lst, $(this));
         });
        $delete.attr('disabled', true);   
}
$(document).ready(function() {
    
    
    
    $lst.change(function(){
        $add.attr('disabled', false);
    });
    $panier.change(function(){
        $delete.attr('disabled', false);
     });
    $add.click(function(){
        add();
    });
    $delete.click(function(){
         remove();
    });
     $lst.keypress(function(event){
         if(event.which==13)
            add();
    });
    $panier.keypress(function(event){
        if(event.which==13)
         remove();
    });
});


testable en ligne ici (j'ai testé avec chromium, c'est impec)
6 janvier 2012 à 16:11:52

Allez pareil je vote OK pour le suivant :)
7 janvier 2012 à 18:52:48

Merci c'est sympa. :)

Mais encore faut-il avoir des idées !
7 janvier 2012 à 21:03:08

pas de pb, si tout le monde s'y met, ça ira.
Quelque chose qui serait pas mal, c'est le drag'n drop .. que je ne connais pas pour le moment, mais que je rêve de faire :D Et je sait que c'est faisable en JQuery.

D'ailleurs, je compte bien apprendre cela dès que je pourrais.

[jQuery] Exercice pour s'entraîner

× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
× Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
  • Editeur
  • Markdown