Les formulaires dynamiques sont vieux comme le client-serveur. Cela peut correspondre par exemple à une liste principale dont le choix d'un élément déclenche la population d'une liste secondaire. Rien de bien sorcier et comme pour pas mal d'autres de choses, un concept relativement simple à coder avec un RAD comme Delphi ou même Visual Basic, qui est devenu un véritable enfer avec la mode des applications WEB. Voyons comment il est possible de faire ce type de choses avec la dernière Form API de Drupal 6.
Comme depuis un moment déjà nous allons continue à torpiller notre liste de courses à qui nous avions récemment ajouté les nouveaux schémas de Drupal 6.
Pour les besoins de l'experience, nous allons ajouter deux nouveaux champs à notre table node_produit : categorie_produit et type_produit. Le but est simple, lors de l'ajout ou de l'édition d'un produit, nous auront une liste permettant de choisir la catégorie (féculents, jus de fruits, légumes, etc.) et ce choix renseignera une seconde liste de types de produit (pâtes, choux, jus d'orange, etc.). Un peu neu-neu, je sais, mais au moins on peut se concentrer sur la technique.
Pour commencer nous allons rapidement modifier le schéma de notre module en ajoutant nos deux champs :
- répondre
Daniel , le 27 September, 2008 - 12:21Merci pour ce tuto très clair, comme d'hab, car la doc officielle n'est pas très prolixe sur AHAH.
Le GROS pb de AHAH, à mon avis, est qu'il envoie tout le form à chaque fois (body compris). Pour une liste de course c'est pas grave mais pour un form un peu plus élaboré (avec pleins de select ayant chacun pleins d'items, et un body un peu conséquent), ça me paraît assez délirant.
J'avais fait un essai pour un besoin de select dépendants (liste d'un select dépendante du choix fait dans un autre select), mais outre la BP consommée, ça donnait des temps de réponse catastrophiques.
Je n'ai d'ailleurs toujours pas compris que l'on ne puisse pas configurer AHAH pour ne poster en ajax que l'élement de form concerné, et pas tout le form (si c'est possible, je suis preneur).
Du coup, je me suis rabattu sur un fichier js ad hoc à la place de AHAH.
Les détails sur http://drupalfr.org/node/4492
- répondre
Ulhume, le 27 September, 2008 - 18:22@Daniel ben là tu me vois surpris :
$element = $form['wrapper-types']['type_produit'];
// Transformation de l'élément en HTML
$output = drupal_render($element)
// On renvoie au client le formulaire sous sa forme HTML, convertie en JSON
print drupal_to_js(array('data' => $output, 'status' => true))
Comme tu le vois, c'est bien l'élément, la liste déroulante (SELECT), que j'envoie par ce canal, absolument pas le formulaire complet..
Ou alors j'ai pas compris où tu voulais en venir.
- répondre
Ulhume, le 27 September, 2008 - 18:34@Daniel je viens de vérifier au cas où avec firebug et lors d'une sélection d'Item, j'ai juste le formulaire qui est posté au serveur, et en réponse, j'ai juste l'élément à utiliser pour remplacer l'ancienne liste.
- répondre
Daniel , le 27 September, 2008 - 21:20Oui, c'est ce que je voulais dire, lors de l'appel ajax client->serveur, TOUT le formulaire est transmis, la réponse c'est toi qui gère donc tu peux mettre ce que tu veux, mais pour l'appel, le formulaire complet peut être très gros, si tu l'envoies en entier à chaque clic dans chaque select, c'est vraiment trop bourrin, et j'ai pas trouvé comment configurer la bestiole autrement.
- répondre
Ulhume, le 27 September, 2008 - 21:57@Daniel Pour avoir étudié les sources (misc/AHAH.js) il n'y a pas de moyen de configurer cela plus finement, effectivement, mais c'est aussi assez logique. Comme je le disais en intro AHA est une version simplifiée d'AJAX, d'où le côté bourrin mais aussi que tu peux mettre entre toutes les mains. La finesse dont tu parles implique de coder toi-même tes requêtes ce qui est facilement faisable avec jQuery.
Maintenant j'aurais tendance à dire aussi que si tu as un formulaire si long qu'un simple POST de celui-ci draine tes ressources, c'est qu'il est trop long et qu'il te faudrait un multi-part, ne serait-ce que pour des raisons de lisibilité et d'utilisabilité.
- répondre
Daniel , le 27 September, 2008 - 23:22Oui, c'est ce que j'ai fait, et effectivement ça fait plutôt moins de lignes de code js que le php pour déclarer ahah dans le module, c'est juste qu'il faut se remettre à js, avec la syntaxe jQuery et la surcouche drupal (je me plains pas, le Drupal.behaviors est bien pratique).
C'est pas ça qui pompe les ressources du serveur, mais ça rend la réaction plus lente (surtout si le client a un débit moyen), chaque POST peut dépasser 20ko là où qq centaines d'octets suffisent en js.
J'était juste étonné de ce gaspillage de BP, et qu'il n'y ait pas moyen de se limiter au select concerné avec ahah.
Je n'ai pas fait de mesures, mais à vue de nez on gagne largement un facteur 10 à la réactualisation des selects (à chaque clic dans un select concerné).
La différence est probablement nettement moins perceptible dans un cas comme ton exemple (le form complet ne doit pas dépasser 2-3ko).
- répondre
Ulhume, le 28 September, 2008 - 00:38@Daniel Lorsque je parle de ressources, c'était bien de bande passante qu'il s'agissant
La raison qui fait que AHAH gaspille ainsi la BP c'est qu'il n'y a pas de protocole remontant du client vers le serveur à proprement parler dans ce concept. Il POST le formulaire et ça s'arrête là. JSON c'est uniquement pour la descente.
Maintenant c'est pas non plus la méthode que j'utilise mais c'est de loin la plus simple pour qui n'est pas développeur. Perso je préfère la méthode JQery avec mon module AJAD
Si tu veux je peux la mettre en plus.
- répondre
zmove , le 21 October, 2008 - 16:04Est-il possible d'appliquer une variable au path appelé par ahah ? Je m'explique
J'ai 2 listes déroulantes, la premiere permet de séléctionner un node, et la deuxième affiches les attributs disponible pour ce node.
j'ai donc besoin d'avoir un path contenant le $nid afin de charger ensuite la bonne liste d'attributs. Voici ce que j'ai pour le moment.
J'aurais donc besoin de faire quelque chose dans le genre j'imagine :
<?php
//...
'#ahah' => array(
'path' => 'uc_discounts_product/js/$nid',
//...
?>
Le problème c'est que $nid doit être l'id du node que je séléctionne dans cette même liste, je ne peux donc le savoir via PHP car c'est une donnée qui varie dynamiquement (en fonction du produit que je séléctionne dans ma liste).
Comment je peux donc afficher une liste dépendante de la valeur séléctionnée dans la liste précédente ?
Poster un nouveau commentaire