Je sais que XHTML ne prend pas en charge les balises de formulaire imbriquées et j'ai déjà lu d'autres réponses ici sur Stack Overflow à ce sujet, mais je n'ai toujours pas trouvé de solution élégante au problème.
Certains disent que vous n'en avez pas besoin et qu'ils ne peuvent pas penser à un scénario où cela serait nécessaire. Eh bien, personnellement, je ne peux pas penser à un scénario dont je n'ai pas besoin.
Voyons un exemple très simple:
Vous créez une application de blog et vous avez un formulaire avec des champs pour créer un nouveau message et une barre d'outils avec des "actions" comme "Enregistrer", "Supprimer", "Annuler".
<form
action="/post/dispatch/too_bad_the_action_url_is_in_the_form_tag_even_though_conceptually_every_submit_button_inside_it_may_need_to_post_to_a_diffent_distinct_url"
method="post">
<input type="text" name="foo" /> <!-- several of those here -->
<div id="toolbar">
<input type="submit" name="save" value="Save" />
<input type="submit" name="delete" value="Delete" />
<a href="/home/index">Cancel</a>
</div>
</form>
Notre objectif est d'écrire le formulaire d'une manière qui ne nécessite pas JavaScript , juste un vieux formulaire HTML et des boutons d'envoi.
Étant donné que l'URL d'action est définie dans la balise Form et non dans chaque bouton d'envoi individuel, notre seule option est de publier sur une URL générique, puis de commencer "si ... alors ... sinon" pour déterminer le nom du bouton qui a été soumis. Pas très élégant, mais notre seul choix, car nous ne voulons pas compter sur JavaScript.
Le seul problème est qu'en appuyant sur "Supprimer", tous les champs du formulaire seront soumis sur le serveur, même si la seule chose nécessaire pour cette action est une entrée cachée avec le post-id. Pas très grave dans ce petit exemple, mais j'ai des formulaires avec des centaines (pour ainsi dire) de champs et d'onglets dans mes applications LOB qui (en raison des exigences) doivent tout soumettre en une seule fois et en tout cas cela semble très inefficace et un gaspillage. Si l'imbrication des formulaires était prise en charge, je serais au moins capable d'envelopper le bouton de soumission «Supprimer» dans son propre formulaire avec uniquement le champ post-id.
Vous pouvez dire "Il suffit d'implémenter le" Supprimer "comme lien au lieu de soumettre". Ce serait faux à tant de niveaux, mais surtout parce que les actions à effet secondaire comme «Supprimer» ici, ne devraient jamais être une demande GET.
Donc ma question (en particulier à ceux qui disent qu'ils n'ont pas eu besoin d'imbrication de forme) est Que faites-vous? Y a-t-il une solution élégante qui me manque ou la ligne de fond est vraiment "soit exiger JavaScript ou tout soumettre"?
Réponses:
J'implémenterais cela exactement comme vous l'avez décrit: soumettez tout au serveur et faites un simple if / else pour vérifier sur quel bouton vous avez cliqué.
Et puis j'implémenterais un appel Javascript lié à l'événement onsubmit du formulaire qui vérifierait avant que le formulaire ne soit soumis, et ne soumettrais que les données pertinentes au serveur (éventuellement via un second formulaire sur la page avec l'ID nécessaire pour traiter la chose comme une entrée masquée, ou actualisez l'emplacement de la page avec les données dont vous avez besoin transmises en tant que demande GET, ou effectuez une publication Ajax sur le serveur, ou ...).
De cette façon, les personnes sans Javascript peuvent très bien utiliser le formulaire, mais la charge du serveur est compensée car les personnes qui ont Javascript ne soumettent que la seule donnée nécessaire. Se concentrer uniquement sur le soutien de l'un ou de l'autre limite vraiment inutilement vos options.
Alternativement, si vous travaillez derrière un pare-feu d'entreprise ou quelque chose et que tout le monde a désactivé Javascript, vous voudrez peut-être faire deux formulaires et travailler un peu de magie CSS pour donner l'impression que le bouton de suppression fait partie du premier formulaire.
la source
Je sais que c'est une vieille question, mais HTML5 offre quelques nouvelles options.
La première consiste à séparer le formulaire de la barre d'outils dans le balisage, à ajouter un autre formulaire pour l'action de suppression et à associer les boutons de la barre d'outils à leurs formulaires respectifs à l'aide de l'
form
attribut.Cette option est assez flexible, mais le message d'origine a également mentionné qu'il peut être nécessaire d'effectuer différentes actions avec un seul formulaire. HTML5 vient à la rescousse, encore une fois. Vous pouvez utiliser l'
formaction
attribut sur les boutons d'envoi, afin que différents boutons du même formulaire puissent envoyer des URL différentes. Cet exemple ajoute simplement une méthode de clonage à la barre d'outils en dehors du formulaire, mais cela fonctionnerait de la même manière imbriquée dans le formulaire.http://www.whatwg.org/specs/web-apps/current-work/#attributes-for-form-submission
L'avantage de ces nouvelles fonctionnalités est qu'elles font tout cela de manière déclarative sans JavaScript. L'inconvénient est qu'ils ne sont pas pris en charge sur les anciens navigateurs, vous devrez donc effectuer un polyfilling pour les anciens navigateurs.
la source
form=
sert le navigateur - CanIUse ne le dit pas vraiment. caniuse.com/#feat=forms<input>
pour déclarer des boutons. l'<button>
élément a été introduit il y a 15 ans à cet effet. Vraiment des gens.<input>
ou des<button>
éléments n'a pas d'importance, bien que les boutons soient généralement plus appropriés pour les barres d'outils, comme vous le dites. Soit dit en passant, les éléments des boutons ne sont pas pris en charge par tous les navigateurs depuis 15 ans.pouvez-vous avoir les formulaires côte à côte sur la page, mais pas imbriqués. puis utiliser CSS pour aligner tous les boutons?
la source
HTML5 a une idée de «propriétaire de formulaire» - l'attribut «formulaire» pour les éléments d'entrée. Il permet d'émuler des formes imbriquées et résoudra le problème.
la source
Type de vieux sujet, mais celui-ci pourrait être utile pour quelqu'un:
Comme quelqu'un l'a mentionné ci-dessus - vous pouvez utiliser un formulaire factice. J'ai dû surmonter ce problème il y a quelque temps. Au début, j'ai totalement oublié cette restriction HTML et j'ai juste ajouté les formulaires imbriqués. Le résultat était intéressant - j'ai perdu ma première forme du niché. Ensuite, il s'est avéré être une sorte de "truc" pour simplement ajouter un formulaire factice (qui sera supprimé du navigateur) avant les formulaires imbriqués réels.
Dans mon cas, cela ressemble à ceci:
Fonctionne très bien avec Chrome, FireFox et Safari. IE jusqu'à 9 (pas sûr environ 10) et Opera ne détecte pas les paramètres dans le formulaire principal. Le global $ _REQUEST est vide, quelles que soient les entrées. Les formes intérieures semblent bien fonctionner partout.
Je n'ai pas testé une autre suggestion décrite ici - fieldset autour des formulaires imbriqués.
EDIT : Frameset n'a pas fonctionné! J'ai simplement ajouté le formulaire principal après les autres (plus de formulaires imbriqués) et utilisé le "clone" de jQuery pour dupliquer les entrées du formulaire en cliquant sur le bouton. Ajout de .hide () à chacune des entrées clonées pour garder la disposition inchangée et maintenant cela fonctionne comme un charme.
la source
Je pense que Jason a raison. Si votre action "Supprimer" est minime, faites-la sous une forme seule et alignez-la avec les autres boutons afin de faire ressembler l'interface à une forme unifiée, même si ce n'est pas le cas.
Ou bien sûr, repensez votre interface et laissez les gens supprimer complètement ailleurs, ce qui ne les oblige pas du tout à voir l'énorme forme.
la source
Une façon de le faire sans javascript serait d'ajouter un ensemble de boutons radio qui définissent l'action à entreprendre:
Ensuite, le script d'action prendrait différentes actions en fonction de la valeur de l'ensemble de boutons radio.
Une autre façon serait de mettre deux formulaires sur la page comme vous l'avez suggéré, mais pas imbriqués. La disposition peut cependant être difficile à contrôler:
Utilisation du champ "tâche" masqué dans le script de gestion pour créer une branche appropriée.
la source
Cette discussion m'intéresse toujours. Derrière le message d'origine, il y a des "exigences" que l'OP semble partager - c'est-à-dire un formulaire avec une compatibilité descendante. En tant que personne dont le travail au moment de la rédaction doit parfois revenir à IE6 (et pour les années à venir), je creuse cela.
Sans pousser le cadre (toutes les organisations vont vouloir se rassurer sur la compatibilité / robustesse, et je n'utilise pas cette discussion comme justification du cadre), les solutions Drupal à ce problème sont intéressantes. Drupal est également directement pertinent car le framework a une politique de longue date "il devrait fonctionner sans Javascript (uniquement si vous le souhaitez)", c'est-à-dire le problème du PO.
Drupal utilise ses fonctions form.inc assez étendues pour trouver le triggering_element (oui, c'est le nom dans le code). Voir le bas du code répertorié sur la page API pour form_builder (si vous souhaitez creuser dans les détails, la source est recommandée - drupal-x.xx / includes / form.inc ). Le générateur utilise la génération automatique d'attributs HTML et, via cela, peut en retour détecter le bouton sur lequel vous avez appuyé et agir en conséquence (ceux-ci peuvent également être configurés pour exécuter des processus distincts).
Au-delà du générateur de formulaires, Drupal divise les actions de suppression de données en URL / formulaires séparés, probablement pour les raisons mentionnées dans le message d'origine. Cela nécessite une sorte d'étape de recherche / référencement ( gémir un autre formulaire !, mais est convivial) au préalable. Mais cela a l'avantage d'éliminer le problème "soumettre tout". Le grand formulaire avec les données est utilisé dans le but prévu, la création / mise à jour des données (ou même une action de «fusion»).
En d'autres termes, une façon de contourner le problème est de décomposer le formulaire en deux, puis le problème disparaît (et les méthodes HTML peuvent également être corrigées via un POST).
la source
Utilisez un
iframe
pour le formulaire imbriqué. S'ils ont besoin de partager des champs, alors ... ce n'est pas vraiment imbriqué.la source
Ma solution est que les boutons appellent les fonctions JS qui écrivent puis soumettent des formulaires en dehors du formulaire principal
la source
Si vous ne voulez vraiment pas utiliser plusieurs formulaires (comme le suggère Jason), utilisez des boutons et des gestionnaires onclick.
Et puis en javascript (j'utilise jQuery ici pour plus de facilité) (même si c'est assez exagéré pour ajouter des gestionnaires onclick)
Je sais aussi que cela fera que la moitié de la page ne fonctionnera pas sans javascript.
la source
En réponse à une question postée par Yar dans un commentaire à sa propre réponse, je présente du JavaScript qui redimensionnera un iframe. Dans le cas d'un bouton de formulaire, il est sûr de supposer que l'iframe sera sur le même domaine. C'est le code que j'utilise. Vous devrez modifier les mathématiques / constantes de votre propre site:
Ensuite, appelez-le comme ceci:
la source
Je viens de trouver une belle façon de le faire avec jquery.
la source
Eh bien, si vous soumettez un formulaire, le navigateur envoie également un nom et une valeur de soumission d'entrée. Donc ce que vous pouvez faire c'est
donc côté serveur, il vous suffit de rechercher le paramètre qui démarre la chaîne de largeur "action:" et la partie restante vous indique quelle action entreprendre
donc quand vous cliquez sur le bouton Enregistrer le navigateur vous envoie quelque chose comme foo = asd & action: save = Save
la source
J'ai contourné le problème en incluant une case à cocher selon la forme que la personne voulait faire. Ensuite, j'ai utilisé 1 bouton pour envoyer le formulaire complet.
la source
Alternativement, vous pouvez attribuer le formulaire actiob à la volée ... ce n'est peut-être pas la meilleure solution, mais vous soulagez certainement la logique côté serveur ...
la source