network : antoine.guiral.info bertrand.guiral.info

[tuto jquery] drag ‘n drop avec sauvegarde automatique en base de données (2/2)

Ça y est, la suite est enfin là! Dans la première partie de ce tutoriel nous avions vu comment faire un drag’n drop avec jQuery. Maintenant nous allons voir comment effectuer notre sauvegarde automatique grâce à l’AJAX. Il y a deux modifications majeures à apporter à notre code. La première est la partie base de données : création des tables, des requêtes,etc… La seconde est l’ajout d’un traitement lors d’un drop d’ingrédient dans une recette. Autrement dit, effectuer les requêtes au bon moment.

  • La BDD

Notre base sera composée de 3 tables :

  • la table recette sera composée d’un identifiant (id_recette) et d’un nom de recette (recette).
  • la table ingrédient avec un identifiant (id_ingredient) et le nom de l’ingrédient (ingredient).
  • la table recette_ingredient qui contiendra les compositions de nos recettes sous la forme de couples id_recette,id_ingredient.

Cette organisation vient de nos cardinalités : un ingrédient peut être dans plusieurs recettes et une recette peut contenir plusieurs ingrédients.

Voici le code SQL pour créer les tables :

  1.  
  2. CREATE DATABASE `tuto_drag` ;
  3.  
  4. CREATE TABLE `recettes` (
  5. `id_recette` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
  6. `recette` VARCHAR( 50 ) NOT NULL
  7.  
  8. ) ENGINE = innodb;
  9.  
  10. CREATE TABLE `ingredients` (
  11. `id_ingredient` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
  12. `ingredient` VARCHAR( 50 ) NOT NULL
  13.  
  14. ) ENGINE = innodb;
  15.  
  16. CREATE TABLE `recette_ingredient` (
  17. `refid_ingredient` INT NOT NULL ,
  18. `refid_recette` INT NOT NULL
  19.  
  20. ) ENGINE = INNODB CHARACTER SET latin1 COLLATE latin1_swedish_ci
  21.  
  22. ALTER TABLE `recette_ingredient` ADD PRIMARY KEY ( `id_ingredient` , `id_recette` )
  23.  
  24. INSERT INTO `ingredients` ( `id_ingredient` , `ingredient` )
  25. VALUES (NULL,’oeuf’),(NULL,’sucre’),(NULL,’farine’),(NULL,’sel’),(NULL,’lait’);
  26.  
  27. INSERT INTO `recettes` ( `id_recette` , `recette` )
  28. VALUES (NULL,’Pâte à crêpe’),(NULL,’Pâte brisée’);
  29.  
  • Les traitements coté serveur

Maintenant que nous avons une base de données il faut créer les scripts qui vont nous permettre d’interagir avec elle. Nous devons pouvoir ajouter une recette, un ingrédient et faire nos sauvegarde de composition de recette. Appelons notre fichier “traitement.php”.

  1.  
  2. <?php
  3. // on se connecte à MySQL
  4. $mysql_link=mysql_connect(”localhost”, “root”, “”);
  5. //on selectionne notre base de donnée
  6. mysql_select_db(”tuto_drag”, $mysql_link);
  7.  
  8. //une petite fonction qui permet de proteger votre bdd des injections SQL
  9. function protection($string){
  10. if(ini_get(’magic_quotes_sybase’)) {
  11. $string = str_replace(”””, “‘”,$string);
  12. } else {
  13. $string = stripslashes($string);
  14. }
  15. }
  16.  
  17. return mysql_real_escape_string($string);
  18. }
  19.  
  20. //nous switchons suivant le parametre “action” vers le cas qui nous interesse
  21. switch($_REQUEST['action']){
  22. //je pense que les case sont assez clair
  23. case ‘ajout_ingredient_recette’:
  24. $id_recette=substr($_GET['id_recette'],1,1);
  25. $id_ingredient=$_GET['id_ingredient'];
  26.  
  27. $sql=’insert into recette_ingredient values(\”.$id_recette.’\',\.$id_ingredient.’\')’;
  28. $req=mysql_query($sql) or die(’Erreur SQL !’.$sql.’’.mysql_error());
  29. break;
  30.  
  31. case ’suppression_ingredient_recette’:
  32. $id_recette=substr($_GET['id_recette'],1,1);
  33. $id_ingredient=$_GET['id_ingredient'];
  34.  
  35. $sql=’delete from recette_ingredient where refid_recette=’.$id_recette.’ and refid_ingredient=’.$id_ingredient;
  36. $req=mysql_query($sql) or die(’Erreur SQL !’.$sql.’’.mysql_error());
  37. break;
  38.  
  39. }
  40.  
  41. ?>
  42.  
  • Modification de notre page XHTML

Alors qu’allons nous faire de cette page…Vu que nous voulons ajouter des ingrédients et des recettes dans notre base de données, il faut que nous générions notre page “creation-recette.html” dynamiquement. La première chose à faire est donc de renommer notre fichier en “creation-recette.php”. Ensuite deux petites requêtes, avec deux boucles et en avant guingammmmmmmpppppp!

  1.  
  2. <?php
  3. // on se connecte à MySQL
  4. $mysql_link=mysql_connect(”localhost”, “root”, “”);
  5. //on selectionne notre base de donnée
  6. mysql_select_db(”tuto_drag”, $mysql_link);
  7.  
  8. //requete pour les recettes
  9. $sql=’select * from recettes order by recette’;
  10. $req_recettes=mysql_query($sql);
  11.  
  12. //requete pour les ingredients
  13. $sql=’select * from ingredients order by ingredient’;
  14. $req_ingredients=mysql_query($sql);
  15.  
  16. echo
  17. <html>
  18. <head>
  19.  
  20. <meta http-equiv=”Content-Type” content=”text/html; charset=iso-8859-1″ />
  21. <script type=”text/javascript” src=”jquery.js”></script>
  22. <script type=”text/javascript” src=”interface.js”></script>
  23. <script type=”text/javascript” src=”script.js”></script>
  24. <link rel=”stylesheet” type=”text/css” href=”styles.css” media=”all”/>
  25. </head>
  26. <body>
  27. <div>
  28. <h1>Waouuuuuuuhhhhhh</h1>
  29. <div class=”ingredient”>’;
  30. //une petite boucle pour afficher les ingredients
  31. while($data=mysql_fetch_assoc($req_ingredients)){
  32. echo
  33. <div id=”‘.$data['id_ingredient'].’” class=”drag”>’.$data['ingredient'].’</div>
  34.  
  35. ’;
  36. }
  37. echo
  38. </div>
  39.  
  40. ’;
  41. //une autre boucle pour afficher les recettes…
  42. while($data=mysql_fetch_assoc($req_recettes)){
  43. echo
  44. <div class=”recette” id=”‘.$data['id_recette'].’”>
  45. <h3>’.$data['recette'].’</h3>
  46. <div class=”recette_ingredient”>’;
  47. //…si les recettes ont des ingredients il faut les récuperer et les afficher…
  48. $sql=’select * from recette_ingredient left join ingredients on refid_ingredient=id_ingredient where refid_recette=’.$data['id_recette'];
  49. $req_compo_recette=mysql_query($sql);
  50. //…avec une boucle! sans oublié de rajouter l’attribut recette sinon les drop de suppression ne marcherons plus! Allez y testez!
  51. while($data1=mysql_fetch_assoc($req_compo_recette)){
  52. echo
  53. <div id=”‘.$data1['id_ingredient'].’” class=”drag” recette=”‘.$data['id_recette'].’”>’.$data1['ingredient'].’</div>
  54.  
  55. ’;
  56. }
  57. echo
  58. </div>
  59. </div>
  60.  
  61. ’;
  62. }
  63. echo
  64. </div>
  65.  
  66. </body>
  67. </html>’;
  68. ?>
  69.  
  • Notre script avec l’AJAX (hyper simple au passage :-p)

On reprend le script du premier tutoriel en rajoutant la méthode get qui nous permet de faire de l’AJAX très simplement grâce à jQuery pooooowwwwwaaaaaaaa.

  1.  
  2. //on créé uen fonction pour rendre nos éléments draggable (merci piouPiouM ^^)
  3. function addDraggable(el){
  4. el.Draggable(
  5. {
  6. revert: true,
  7. zIndex: 1000,
  8. ghosting: true,
  9. opacity: 0.7
  10. }
  11. )
  12. };
  13.  
  14. $(document).ready(
  15.  
  16. function()
  17. {
  18. //Nos élements draggable sont définis ici. Ce sont tous les éléments avec la class CSS ‘.drag’.
  19. addDraggable($(’.drag));
  20.  
  21. //le div avec la class ‘.ingredient’ est notre première zone droppable. Elle contient nos ingrédients (original hein!).
  22. $(’.ingredient).Droppable(
  23. {
  24. //elle accept les élément ayant la class ‘drag’
  25. accept : ‘drag’,
  26. //ici cela affecte des classes css suivant que la zone est active ou hover. Pratique pour changer de style au survol.
  27. //activeclass: ‘activeEmplacement’,
  28. //hoverclass: ‘hoverEmplacement’,
  29. //plusieurs zone de tolérance existe. Allez faire un tour sur la doc.
  30. //Ici nous choisissons de pouvoir dropper un élément quand le pointeur de la souris est dans la zone.
  31. tolerance: ‘pointer’,
  32. //on définit ce qu’il va se passer lorsqu’on drop un élément dans la zone. On passe l’élément draggé en paramètre.
  33. ondrop: function (drag)
  34. {
  35. //on récupère l’attribut recette si le drag en possede un
  36. var id_recette=$(drag).attr(’recette’);
  37. //et l’id de l’ingredient pour le cas de la suppression
  38. var id_ingredient=$(drag).attr(’id’);
  39. //si il en possède un on suprime le drag. Cela correspond à si un ingredient d’une recette est enlevé de sa recette.
  40. //supprimez le bloc et testez!
  41. if(id_recette){
  42. $(drag).remove();
  43. //nous utilisons la methode get sur l’objet jQuery ($).
  44. //le premier parametre est la page de script (dans notre cas “traitement.php”)
  45. //le second est un tableau d’arguments sous la forme clé/valeur
  46. $.get(”traitement.php”,{action:”suppression_ingredient_recette”,id_ingredient:id_ingredient,id_recette:id_recette});
  47. }
  48. },
  49. fit: true
  50. }
  51. );
  52. //Ici nous allons dropper nos ingrédient pour construire nos recettes.
  53. $(’.recette_ingredient).Droppable(
  54. {
  55. accept : ‘drag’,
  56. activeclass: ‘activeEmplacement’,
  57. hoverclass: ‘hoverEmplacement’,
  58. tolerance: ‘pointer’,
  59. ondrop: function (drag)
  60. {
  61. //nous récuperons l’id de la recette. Il est contenu dans le div parent de la zone droppabe (allez revoir le xhtml ;-p).
  62. var id_recette=$(this).parents().attr(’id’);
  63. //on clone l’élément draggable. Cela permet de réutiliser un autre élément pour une autre recette!
  64. var drag1 = $(drag).clone();
  65. //nous ajoutons un attribut recette ayant pour valeur l’id de la recette.
  66. $(drag1).attr(’recette’,id_recette);
  67. //puis nous récuperons l’id de l’ingredient…
  68. var id_ingredient=$(drag1).attr(’id’);
  69. //…pour verifier qu’il ne soit pas déjà présent!
  70. if (!$(this).children().is(’#’ + id_ingredient)) {
  71. //s’il n’est pas présent on l’ajoute
  72. $(this).append(drag1);
  73. //on rend notre “clone” draggable
  74. addDraggable(drag1);
  75. //même combat pour l’ajax ^^
  76. $.get(”traitement.php”,{action:”ajout_ingredient_recette”,id_ingredient:id_ingredient,id_recette:id_recette});
  77. //avec un petit effet pour l’apaprition :p
  78. $(drag1).fadeIn(”slow”);
  79. }
  80. },
  81. fit: true
  82. }
  83. );
  84.  
  85. }
  86. );
  87.  
  • Le CSS

Bon ben là je vous renvoi vers la première partie du tutoriel :-).

Voila! C’est fini! Bon j’aurais pu optimiser un peu le code par moment…en factorisant la connexion à la base, en evitant la requette pour chaque recette…mais bon ce n’était pas le but du tuto hein :-p. Si vous voulez vous entrainer vous pouvez par exemple rajouter deux champ qui permettent d’ajouter une recette et un ingrédient en AJAX!

Si vous avez des questions, comme d’hab’ n’hésitez pas je me ferais un plaisir d’essayer d’y répondre! Et montrez moi vos essais! ;-)

Partagez cet article : Ces icônes sont des liens vers des sites de partage de signet sociaux où les lecteurs peuvent partager et découvrir de nouveaux liens.
  • bodytext
  • del.icio.us
  • Facebook
  • Google
  • co.mments
  • De.lirio.us
  • Live
  • Ma.gnolia
  • Pownce
  • Scoopeo
  • Technorati
  • TwitThis
  • Wikio FR
  • e-mail

Laissez un commentaire

28 commentaires pour “[tuto jquery] drag ‘n drop avec sauvegarde automatique en base de données (2/2)”

  1. Bon, là, maintenant, il faut que je me bouge un peu pour tester et comprendre tout ça ;) Merci.

  2. De rien!

    Si tu as besoin de précision n’hésite pas :-) (twit moi ou gtalk) j’ai commenté un peu rapidement certaine partie (notamment le SQL)…

    bon courage! Mais avec tes talent de designer tu va pouvoir faire des truc de ouf! :-p

  3. J’ai une question toute à fait stupide : à quoi servent les “$” dans le code javascript ?
    Il est difficile de faire une recherche la-dessus …
    Cependant, j’ai trouvé ça dans la doc officielle :
    You use variables as symbolic names for values in your application. The names of variables, called identifiers, conform to certain rules.

    A JavaScript identifier must start with a letter, underscore (_), or dollar sign ($); subsequent characters can also be digits (0-9). Because JavaScript is case sensitive, letters include the characters “A” through “Z” (uppercase) and the characters “a” through “z” (lowercase).

    C’est pas très clair…

    Merci par avance, Yves.

  4. Ici nous utilisons un framework javascript qui s’appelle jQuery. Tous les objets jQuery sont identifiés grâce à la variable “$”. Par exemple $(”p”) va retourner un objet jQuery contenant tous les paragraphes (balises p) du document.

    Je répond à ta question?

    A bientôt! (et aucun question n’est stupide!)

  5. Hello,

    Très joli tuto que celui-là. Cela fait pas mal de temps que je cherche un tutoriel de ce genre et je suis donc très content de trouver celui-ci. ;-)
    J’aurais néanmoins une petite requête. Ce que je veux faire est un peu différent. J’ai une liste d’objets “dragables” dont je veux pouvoir changer la position en glissant un objet à une autre place dans la liste et en enregistrant la modification dans une base de donnée. En gros, si je prends le 5ième élément et que je le glisse en 2ième, celui-ci reçoit la position 2, le 2 glisse en 3, le 3 en 4 et le 4 en 5. J’espère que je suis assez clair…

    Existerait-il quelque part un tuto pour faire ce genre de chose ou quelqu’un aurait-il une idée sur la façon de procéder ? Je suis en effet incapable de développer ça tout seul… (snif)

    Merci d’avance !

  6. Salut david,

    oui je vois ce que tu veux faire. Tu parle de liste, tu as une liste au sens html? c’est à dire balise ul/li ou ol/li?

    Merci pour les compliments sur le tuto ;-)
    A bientôt

  7. En fait là je les ai mis dans un div mais à la base c’est une liste.

    <img src="../images/gestion/icone_page.png" alt="" width="80" height="80" /><a href="contenu.php?id= ">

    C’est un while qui parcourt la base de données et sort toutes les pages. Ces pages ont un champs position sur lequel je veux faire des modifications.

    Merci pour l’aide (et rapide en plus).

  8. Tu aurais une page d’exemple? Si c’est une liste il existe des truc tout fais pour ça tu n’aurais plus qu’à t’occuper de la partie sauvegarde en bdd. Dès que j’ai un exemple de ce que tu veux faire je t’envoie les liens (pour être sûr que c’est ce que tu veux :-)).

  9. Je te mets plus de code et je le mets en liste pour que tu voie ce que c’est et un lien vers une image de la page (c’est sécurisé je saurais pas te la montrer).

    <img src="../images/gestion/icone_page.png" alt="" width="80" height="80" /><a href="contenu.php?id= ">

    L’image

    Ce sont les blocs entourés en pointillés.

  10. Oui c’est galère de mettre du code dans les commentaires,

    je pense que tu trouvera ton bonheur ici : http://interface.eyecon.ro/demos avec les sortables lists ou sortables floats . Ensuite il faut que tu adapte le code pour faire la sauvegarde en bdd. Une fois que tu auras coder le “sortable” contact moi par mail je pourrais te filer un coup de main.

    Au passage : le design de ta page est super.

  11. OK je regarde ça demain et je te tiens au courant.
    Encore merci !

  12. ok ca marche! Avec plaisir!

    A bientôt!

  13. Hello,

    J’essaye d’implémenter le script interface pour rendre mes blocs tribales mais je n’y arrive pas.

    Je ne vois pas ce qui ne fonctionne pas j’ai pourtant suivi cet exemple.

    Je suppose que j’ai dû faire une erreur mais je ne vois pas où… Une idée ?

  14. Bon décidément ça ne passe pas pour le code.

    J’ai mis la page dans un dossier test de manière à ce que tu puisse regarder le code.

  15. Je viens de regarder ton code tu as des erreurs de compil. Corrige déjà ca on verra pour la suite :-) J’ai aussi vu que tu avais du html dans un fichier js :s pas tres coherent.. Je te passe mon gmail : guiral[.]antoine[at]gmail[.]com

    Courage ;-)

  16. Bonjour,

    Bon script, probablement le plus clair parmi tous les tuto fr que j’ai trouvé.
    Cependant j’ai deux petites questions :

    A quoi ça sert de mettre “substr” ici $id_recette=substr($_GET[’id_recette’],1,1); cat si ton id_recette fait “25″ il ne va te sortir que “2″ !?

    Et aussi : $sql=’insert into recette_ingredient values(\”.$id_recette.’\’,\”.$id_ingredient.’\’)’; si tu ne précises pas les champs à remplir comment peut-il enregistrer ?

    @+
    Manu

  17. Bonjour emmanuel,
    tout d’abord merci pour le compliment (en plus cela correspond assez bien à ton site ;-))!

    Ensuite pour les deux points que tu abordes : en e qui concerne le substr en effet il ne ressortira que le 2. A vrai dire je ne m’ettais même pas posé la quetion la “difficulté” du tuto n’étant pas là. Mais si j’ai le temps un de ces 4 je ferais la modif (ca y est c’est sur mon todo).

    Par contre pour la requête cela fonctionne. Ma table contient deux champs, si je lui envoi le bon nombre d’info dans le bon ordre c’est ok. Sinon il faut en effet préciser le noms des champs dans lesquels on veut faire l’insert.
    A bientôt!

    (

  18. Bonjour Antoine,

    En effet, j’avais oublié qu’il était possible d’écrire un insert into de cette manière, en ce qui me concerne, je ne le fais jamais car j’ai toujours peur qu’en cas de surcharge du serveur ce dernier s’emmêle les pinceaux dans l’interprétation de la requête alors je reste très précis dans ces dernières.

    Sinon pour en revenir au script, étant nul en ajax je me creuse la tête depuis plusieurs heures pour ajouter une amélioration, à savoir, lorsque, pour reprendre l’exemple, l’on ajoute un ingrédient pour la recette j’aimerai que cet ingrédient devienne rouge dans la liste des ingrédients (ou n’importe quelle autre couleur), afin de montrer qu’il a déjà été utilisé et de même, retirer la couleur si l’on retire l’aliment de la recette. J’aimerai utilisé ton script de la sorte pour remplir une liste d’objets afin de mieux voir ceux qui ont déjà été ajouté à la liste.

    Bref si tu pouvais m’aider sur ce coup ça serai super !

    Manu

  19. Salut manu,

    alors j’ai un peu réfléchit à ce que tu veux faire…la première chose à faire c’est créer les classes CSS que tu appliquera à tes éléments. Ensuite je pense que tu peux procéder de deux manières : la première serait de modifier le script en profondeur et d’associer à chaque zone droppable un array et ensuite de comparer les arrays afin d’appliquer le style aux doublons. La seconde consisterais à appliquer le style au moment ou tu clones ton élément dans ta liste d’objets et à l’enlever au moment ou tu tue ton drag.

    Mais dans les deux cas cela sous entend que tu ne gère qu’une recette parce que comment faire comprendre qu’un ingrédient à été utilisé dans une recette parmi celles affichés?

    Bon courage et tiens nous au courant de tes avancées ;-)