28sept/1148

Tutoriel: Drag and drop jQuery / AJAX

Publié par Sébastien dans Développement, Tutoriel

L'apparition du drag and drop sur la toile ne date pas d'hier, et cela peut s'avérer très utile dans un back office, par exemple pour gérer l'ordre des éléments d'un menu ou d'une galerie d'images.

Mais pour que ce soit vraiment puissant, il faut bien évidemment que les modifications soient enregistrées en base de données, et en temps réel!

Guillaume Voisin a présenté un tutoriel très clair sur la façon de mettre en place un système de drag and drop dans son article Drag and Drop jQuery. C'est pourquoi, à partir de cette base, je me limiterai à la partie sauvegarde en live en base de données.

Voir la DEMO - Télécharger l'archive

Base de données

Avant de se lancer dans le code, il faut avant tout avoir une table en base de données avec au minimum l'architecture suivante:

Structure de la table en base de données

Structure de la liste HTML

On va pouvoir reprendre la liste HTML du tutoriel de Guillaume Voisin à un petit détail près: il faut préciser pour chaque ligne l'identifiant en base de données de l'élément affiché.

<ul>
	<li id="Element_1">Milk</li>
	<li id="Element_2">Red wine</li>
	<li id="Element_3">Sugar</li>
	<li id="Element_4">Ice Cream</li>
</ul>

Mise en place du drag and drop

Comme dit précédemment, le tutoriel de Drag and Drop jQuery de Guillaume Voisin explique en détail comment mettre en place une liste qu'on peut facilement réordonner à l'aide du drag and drop.

On va donc partir de cet exemple en se limitant à la partie "tri drag and drop" de la liste, pour ajouter le code nécessaire à la mémorisation en base de données.

Vous devrez donc avoir dans le fichier appelé jquery.shoppingList.js le code suivant:

$(obj).sortable({
	axis: "y", // Le sortable ne s'applique que sur l'axe vertical
	containment: ".shoppingList", // Le drag ne peut sortir de l'élément qui contient la liste
	handle: ".item", // Le drag ne peut se faire que sur l'élément .item (le texte)
	distance: 10, // Le drag ne commence qu'à partir de 10px de distance de l'élément
	// Évènement appelé lorsque l'élément est relâché
	stop: function(event, ui){
		// Pour chaque item de liste
		$(obj).find("li").each(function(){
			// On actualise sa position
			index = parseInt($(this).index()+1);
			// On la met à jour dans la page
			$(this).find(".count").text(index);
		});
	}
});


C'est dans ce code que nous allons pouvoir intégrer un appel à la mise à jour de l'ordre des éléments de la liste.

Appel de la mise à jour

On va maintenant demander à notre code jQuery d'appeler une page, qu'on appellera updateListe.php, contenant un script php qui va mettre à jour la position des éléments en base de donnée.

Il suffit donc d'ajouter dans le code précédent le code suivant:

update: function()
{
	// On prépare la variable contenant les paramètres
	var order = $(this).sortable("serialize")+'&action=updateListeOrder';
	// $(this).sortable("serialize") sera le paramètre "element", un tableau contenant les différents "id"
	// action sera le paramètre qui permet éventuellement par la suite de gérer d'autres scripts de mise à jour

	// Ensuite on appelle notre page updateListe.php en lui passant en paramètre la variable order
	$.post("/updateListe.php", order, function(theResponse){});
} 

Il est possible de récupérer une réponse du script pour afficher un message à l'utilisateur. Notre script jQuery final (pour la partie concernant le tri) aura donc cette allure:

$(obj).sortable({
	axis: "y", // Le sortable ne s'applique que sur l'axe vertical
	containment: ".shoppingList", // Le drag ne peut sortir de l'élément qui contient la liste
	handle: ".item", // Le drag ne peut se faire que sur l'élément .item (le texte)
	distance: 10, // Le drag ne commence qu'à partir de 10px de distance de l'élément
	// Évènement appelé lorsque l'élément est relâché
	stop: function(event, ui){
		// Pour chaque item de liste
		$(obj).find("li").each(function(){
			// On actualise sa position
			index = parseInt($(this).index()+1);
			// On la met à jour dans la page
			$(this).find(".count").text(index);
		});
	},
	update: function()
	{
		// On prépare la variable contenant les paramètres
		var order = $(this).sortable("serialize")+'&action=updateListeOrder';
		// $(this).sortable("serialize") sera le paramètre "element", un tableau contenant les différents "id"
		// action sera le paramètre qui permet éventuellement par la suite de gérer d'autres scripts de mise à jour

		// Ensuite on appelle notre page updateListe.php en lui passant en paramètre la variable order
		$.post("/updateListe.php", order, function(theResponse)
		{
			// On affiche dans l'élément portant la classe "reponse" le résultat du script de mise à jour
			$(".reponse").html(theResponse).fadeIn("fast");
			setTimeout(function()
			{
				$(".reponse").fadeOut("slow");
			}, 2000);
		});
	}
});

Script de mise à jour de la base de données

Il ne reste maintenant plus qu'à lancer le script de mise à jour de la base de données.

On va donc créer notre fichier updateListe.php, à qui on va passer en paramètre l'action à effectuer ainsi que le tableau des identifiants de chaque élément.

Le fichier va contenir le script suivant:

// On se connecte à notre base de données
$host = "myDBServer";
$user = "myDBUser";
$db = "myDBName";
$pass = "myDBPassword";

mysql_connect($host, $user, $pass) or die(mysql_error());
mysql_select_db($db) or die(mysql_error());

// On analyse la variable POST action (qui permet éventuellement de gérer plusieurs scripts de mise à jour)
if( $_POST['action'] == "updateListeOrder")
{
	// On récupère le tableau des ID de chaque élément
	$elements = $_POST['element']

	// On indique le premier indice de position souhaité
	$position = 1;

	// Et on met à jour la base de données
	foreach($elements as $id)
	{
		$sql = 'UPDATE rubriques SET position = '.$position.' WHERE id='.$id;
		mysql_query($sql) or die(mysql_error());
		$position++;
	}
}

Conclusion

Vous avez maintenant tout ce qu'il faut pour que votre drag and drop mémorise en temps réel la position de vos éléments en base de données.

A partir de là, vous pouvez faire évoluer ce script pour que toutes les actions du tutoriel de Guillaume Voisin soient aussi mémorisées dans la table de vos éléments!

Commentaires (48) Trackbacks (1)
  1. ce drag and drop est exactement ce qu’il me faut, sauf qu’il ne fonctionne pas avec explorer. avez-vous une astuce, ou un lien vers un autre code qui fait la même chose (modif de la base de donnée) et compatible explorer ?
    merci d’avance,

    petite fée

    • Alors effectivement il y a un petit problème, mais seulement avec IE9 (sur les versions précédentes ça fonctionne à priori). Il semblerait que ce soit le drag-and-drop qui ne fonctionne pas, sûrement une petite erreur de ma part lors de la reprise du code de Guillaume Voisin, puisque son tuto est sensé fonctionner sous IE9.
      Je travaille sur mac, du coup je regarderais tout ça dès que j’ai accès à un PC !

      • Bonjour Sébastien, et merci de ta réponse.
        je découvre le jquery, et il me semble évident que je dois apprendre et intégrer maintenant ce fonctionnement dans la construction de mes sites.
        je tatonne donc, et je suis prise par le temps.
        je suis allée voir le tuto d’origine de Guillaume voisin, mais sa démo de drag and drop ne fonctionne pas non plus avec mon explorer 9… firefox est ok par contre.

        le problème ne vient donc pas de toi.

        peut-être as-tu une idée, ou quelqu’un en visite sur ce forum, pour régler ce problème ?
        soit par une correction du code (je ne maitrise pas encore assez cette technique pour le faire) ou en m’indiquant une autre source drag and drop compatible explorer 9 ?

        d’avance merci,

        Petite fée

        • Re-bonjour

          Problème corrigé, il suffisait de mettre à jour les librairies jQuery et le tour est joué!

          Ce tuto drag and drop fonctionne donc pour, à priori, tous les navigateurs (Firefox, Chrome, Safari, Opera, IE9, IE8, IE7)

          • Merci beaucoup,
            pour ta rapidité d’intervention et aussi ton travail.
            pas facile de trouver des tutos et des sources qui fonctionnent simplement, et surtout, EN FRANCAIS !!

            chapeau m’sieur :o)

  2. excellent! mais il me semble que l’exemple live n’est pas tout à fait iso avec le code dans la page ou dans l’archive.
    perso, en partant de l’archive, la sauvegarde du nouvel ordre en base est OK, mais suite à un refresh de la page, l’ordre n’est pas rétabli :-(

  3. Bonjour deadfish,
    tu as bien vérifié que dans la base l’odre est bien le bon ?
    parce que :
    soit l’ordre est bon sur ta vérif sur la page mais pas dans la base ce qui pourrait venir d’un problème de ta requête (update…)
    soit la base est bien mise à jour quand tu regardes dedans, et c’est le refresh qui n’est pas bon, peut-être parce que ton navigateur te réaffiche ta page d’après une archive conservée en cache.
    vérifies les données dans ta base après avoir fait ton glissé-déposé, mais AVANT de rafraichir la page.
    encore une idée : ta requête d’affichage se fait avant ou après la requête update ?
    il est possible qu’en raffraichissant ta page celle-ci conserve les anciens emplacement (et donc le précédent array), et que ta requête d’update se re-lance et remodifie la base (c’est pourquoi je te propose de vérifier les données de ta base avant de rafraichir la page)

    @ +
    Elizabeth

  4. Bonjour,

    j’essaye de faire fonctionner votre script sans trop de succès malheureusement. J’ai aucun action d’enregistrement qui ce fait dans MYSQL.

    if( $_POST['action'] == « updateListeOrder ») devrait être if( $_GET['action'] == « updateListeOrder »)

    Merci de votre aide

    Christophe

  5. bonjour,
    même problème pour moi,
    le message « positions mise à jour » n’apparait pas comme il le fait dans la démo,
    et la base de donnée n’est pas modifiée…
    christophe, as-tu trouvé la solution ?

  6. Alors il y a trois points où il faut faire attention en reprenant le code source du tuto:

    1) dans le fichier index, bien remplacer « nom » dans $res['nom'] par le nom de votre élément dans la table
    2) dans jquery.shoppingList.js, vérifier que l’url passé en paramètre de la fonction $.post est correct, c’est ce qui permet la mise à jour.
    3) vérifier que les paramètres d’accès à la DB sont corrects dans le fichier db.php

    Si ça ne fonctionne toujours pas, vous pouvez encore essayer de mettre à jour vos fichiers jquery.min.s et jquery-ui.custom.min.js, mais à priori c’est sensé fonctionner avec ceux de l’archive…

  7. Dans jquery.shoppingList.js, enlever le premier « / » à la ligne 47 (Modification de l’URL)

    Remplacer /inc/updateListe.php
    Par inc/updateListe.php

    La mise à jour devrais se faire.

  8. Merci pour le tuto,
    le jquery fonctionne bien, mais pas la mise à jour, lorsque je drag un élément, j’ai le message « no datables selected », pourtant, j’ai bien sélectionné ma base de données et vérifié les chemins…
    Une idée ?

  9. Bonjour Sophie,
    j’ai eu le même problème,
    ajoute simplement un appel à ta base juste avant ta requête :
    mysql_select_db($database_client, $client);
    …et ensuite ta requete …$query = « SELECT * FROM etc.

  10. Merci petite fée,
    en fait le pb ne vient pas du sélect (je suis bien connectée à la base, ma page écho bien le contenu dans la page index), le problème vient de la mise à jour, donc de l’update (la connexion ne semble pas se faire…)

    • Il faut que le fichier qui fait la modification ait accès à la base de données. Si le site y a accès, il peut afficher les données sans problème. En revanche, le fichier qui s’occupe de la modification est appelé en AJAX, du coup il faut qu’il y ait accès lui aussi de la même façon que le site.

  11. j’ai trouvé, j’ai ajouté mysql_select_db avant l’update … il n’y était effectivement pas et bien que familière de ce genre de requête, je l’ai happé!
    Merci !

  12. c’est une erreur que je fais tout le temps…
    et je suis familière aussi !
    du coup c’est ce que je regarde en premier quand ça ne fonctionne pas :o)

  13. Excellent bravo !!

  14. Bonjour,

    pour moi ca fonctionne bien , le tri la bdd ok, je fais une configuration pour un formulaire de contact sur cette base .
    on peut donc afficher les champs dans l’ordre que l’on veut. par contre dans ma BDD j’ai rajouté un booleen ‘valide’ qui devrait passer a 0 quand on met le champ a la poubelle .

    j’ai essayé # trucs mais bon ca marche pas pour le moment.
    une piste ?

    • La fonction de base lorsqu’on met un champ à la corbeille n’a aucune interaction avec la BDD, du coup faut faire un appel AJAX dans la fonction drop, très certainement.

      • OK merci Sébastien, je vais essayer .
        je suppose que pour l’ajout c’est la même chose , appel ajax dans la fonction ajouter.
        Pat

        • Comme pour la mise à jour de l’ordre dans la fonction sortable>update, il faut faire un appel ajax vers un fichier php faisant la MàJ du boolean dans la fonction droppable>drop (dans le fichier original du tuto de Guillaume Voisin).

          • ok merci seb, je vais voir ca.

          • ca marche , quand le champ est mis a la poubelle, la variable ‘valide’ dans la bdd passe à 0 et ne sera plus affiché tant que l’on ne l’aura pas changé.
            également après avoir rajouter un champ, il est enregistré dans la bdd (champ texte simple sans contrôle).
            je vous mets le code des que j’ai un moment si ça intéresse quelqu’un.

          • Bonjour Pat, même si ton post date un peu, pourrais-tu mettre ton code sur le site car j’essaie moi aussi de passer dans la bdd une variable à 0 quand le champ est mis à la poubelle.

            merci d’avance.

  15. Bonjour !
    je reviens par là avec une autre question : est-il possible de faire le drag n drop de façon horizontale au lieu de verticale ?

    je cherche partout, j’ai tenté de modifier les styles, mais rien n’y fait…
    si quelqu’un a une astuce, ou un lien qui pourrait m’aider,
    merci de votre aide !

  16. Bien le bonjour,
    je viens demander un petit coup de main (pas dans la tronche si possible).
    J’aimerais mettre en place ce drag’n drop mais je veux que….hum….

    En gros, j’ai a gauche une liste d’éléments, à droite des div.
    Le but étant que l’élément dragé prenne place dans la div(et non pas en dessus ou en dessous) et bien sur ensuite tout cela sauvegardé en base.

    Je suis totalement débutant en jQuery donc si vous aviez des pistes….

  17. Bonjour,
    Actuellement débutant en Jquery je me suis attaqué àvotre tuto pour réaliser un mini projet.
    Tout d’abord je souhaite vous remercier pour le code très bien détaillé.

    Dans mon projet je souhaite supprimer les lignes dans la base de données.
    Je souhaite récupérer l’Id de la table de l?élément a supprimer et c’est la que ça pose problème

    Voici le code il me manque seulement la récupération de la variable ‘idSup’ pour le reste tout fonctionne car quand j?écris en dur la valeur de la variable ceci fonctionne.

    // Action de la poubelle
    // Initialisation du composant Droppable
    $(".trash").droppable({
    // Lorsque l’on relache un élément sur la poubelle
    drop: function(event, ui){
    var idSup = /* JE SOUHAITE RECUPERER ICI L’ID DE MON ELEMENT SUPPRIME*/
    // On retire la classe "hover" associée au div .trash
    $(this).removeClass("hover");
    // On ajoute la classe "deleted" au div .trash pour signifier que l’élément a bien été supprimé
    $(this).addClass("deleted");
    /*On supprime la ligne dans la base de donnée*/
    $.get("js/deleteNews.php",{idSup: idSup});
    // On affiche un petit message "Cet élément a été supprimé" en récupérant la valeur textuelle de l’élément relaché
    $(this).text(ui.draggable.find(".item").text()+" removed !");
    // On supprimer l’élément de la page, le setTimeout est un fix pour IE (http://dev.jqueryui.com/ticket/4088)
    setTimeout(function() { ui.draggable.remove(); }, 1);

    Si quelqu’un à la solution je suis preneur.
    Merci d’avance.

    • Pour ce qui est de la mise à la corbeille d’un élément, tu trouveras certainement ta réponse dans le tutoriel de Guillaume : http://www.guillaumevoisin.fr/jquery/tutoriel-drag-and-drop-jquery-exemple-avec-une-liste-des-taches

      • Je suis parti de ce tuto puis après j’en suis venu au votre pour la gestion avec base de donnée.

        J’ai donc laissé la gestion de la corbeille comme elle était à la base, comme vous pouvez voir le code que j’ai mi au dessus , c’est celui donné par Guillaume, la seule chose c’est que je ne vois pas comment récupérer l’ID de l’élément supprimé. Dans la fonction updateList on récupére les Id comme ceci
        "var order = $(this).sortable("serialize")+’&action=updateListeOrder’;"
        et je ne vois pas comment adapté ça a ma situation :S

        • Alors dans le script de Guillaume, l’élément concerné par la mise à la corbeille est désigné par ui.draggable.

          De la même façon qu’on récupère le "nom" par ui.draggable.find(".item").text(), il suffit de récupérer le ID là où il apparait dans l’élément.

          • D’accord merci,
            je voulais savoir si je pouvais utiliser la même méthode que vous avez appliqué dans le tuto qui permet de relever le numero de l’élémént a partir de l’id. Je ne comprend pas vraiment comment focntionne cette ligne:
            "var order = $(this).sortable("serialize")+?&action=updateListeOrder?;"
            Puis-je la ré-utiliser ou non?

          • La fonction $(this).sortable("serialize") permet de renvoyer un chaine de caractères contenant les ID dans l’ordre d’apparition des éléments.

            Pour l’utiliser, tout dépend quel est le besoin. Ici la fonction est utilisée pour connaitre non seulement les ID des éléments, mais surtout dans quel ordre ils apparaissent pour mémoriser la position des différents DIV.

          • Et bien moi je voudrai m’en servir uniquement pour récupérer l’ID de l?élément supprimé, je ne veux pas récupérer tous les éléments de la liste. Est ce possible?

          • Alors normalement, plus simplement, ui.draggable.find(".item").attr("id") devrait te retourner "element_1" ou "element_2" etc., bref, l’attribut id de l’élément mis à la corbeille.

            Ensuite il suffit, lors de la récupération de cette variable, de supprimer "element_" pour avoir le id à supprimer.

  18. Merci pour l’aide mais j’avais déjà essayé cette technique et malheureusement ma variable retourné est vide…

  19. C’est bon j’ai trouvé!!
    ui.draggable.attr("id")
    voila la bonne syntaxe :)

    • Salut je serai intéressé d’avoir ton code pour la suppression ainsi que la sauvegarde l’insertion en bdd. cela fait quelques jours que je rame pour trouver une solution.

  20. Le script ne fonctionne pas avec la dernière version de jquery, ce qui est vraiment problématique.

  21. Il y a un problème quand on a que deux éléments.
    Quand j’essaie de remonter en première position, rien ne se fait!
    que l pourrait être le problème ?
    Quand il y a trois éléments, tout marche nickel!

  22. Ca marche super, merci.

  23. Petite coquille cependant dans jquery.shoppingList.js :

    $(elt).html("<span class=’item’>"+$(elt).text()+"</item>");

    devrait être

    $(elt).html("<span class=’item’>"+$(elt).text()+"</span>");

    non ?

  24. c’est supers tutoriels je veux l’utilisé sur tablette mais Drag and Drop ne marche pas avec le doignt est ce que je dois ajouté un scripte ou changé quelque chose

    merci a vous

  25. Super tuto <3

    Par contre petite question,
    Comment le combiné avec un menu horizontal, qui aurait des sous menus verticaux?

    J’ai réussi à convertir pour le coté horizontal, mais ça m’applique la class ui-sortable à mes <ul> de second niveau… :D


Laisser un commentaire

Notifiez-moi des commentaires à venir via email. Vous pouvez aussi vous abonner sans commenter.