Как преодолеть ограничение вложенности HTML-формы? - PullRequest
196 голосов
/ 28 февраля 2009

Я знаю, что xhtml не поддерживает вложенные теги форм, и я уже прочитал другие ответы
здесь в stackoverflow относительно этой темы, но я до сих пор не нашел элегантного решения проблемы.

Некоторые говорят, что вам это не нужно, и что они не могут придумать сценарий, если бы это было необходимо. Ну, лично я не могу придумать сценарий, который мне не нужен.

Давайте рассмотрим очень простой пример:

Вы создаете приложение для блога, и у вас есть форма с некоторыми полями для создания нового поста и панель инструментов с «действиями», такими как «Сохранить», «Удалить», «Отмена».

<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>

Наша цель - написать форму так, чтобы не требовал javascript , просто старую HTML-форму и кнопки отправки.

Поскольку URL-адрес действия определен в теге Form, а не в каждой отдельной кнопке отправки, наш единственный вариант - опубликовать общий URL-адрес и затем запустить «if ... then ... else», чтобы определить имя кнопка, которая была отправлена. Не очень элегантно, но наш единственный выбор, так как мы не хотим полагаться на JavaScript.

Единственная проблема заключается в том, что нажатие кнопки «Удалить» отправит ВСЕ поля формы на сервер, хотя единственное, что необходимо для этого действия, - это скрытый ввод с post-id. В этом небольшом примере нет ничего сложного, но у меня есть формы с сотнями (так сказать) полей и вкладок в моих LOB-приложениях, которые (из-за требований) должны отправлять все за один раз, и в любом случае это кажется очень неэффективным и трата. Если бы вложение форм было поддержано, я бы по крайней мере смог бы обернуть кнопку «Удалить» внутри своей формы, используя только поле post-id.

Вы можете сказать «Просто добавьте« Удалить »как ссылку вместо отправки». Это было бы неправильно на многих уровнях, но самое главное, потому что побочные действия, такие как «Удалить», никогда не должны быть запросом GET.

Итак, мой вопрос (особенно к тем, кто говорит, что им не нужна вложенность форм): что ВЫ делаете? Есть ли какое-нибудь элегантное решение, которое я пропускаю, или в итоге действительно "Либо требуется javascript, либо отправьте все"?

Ответы [ 16 ]

175 голосов
/ 05 декабря 2011

Я знаю, что это старый вопрос, но HTML5 предлагает несколько новых опций.

Первый - это отделить форму от панели инструментов в разметке, добавить другую форму для действия удаления и связать кнопки на панели инструментов с соответствующими формами, используя атрибут form.

<form id="saveForm" action="/post/dispatch/save" method="post">
    <input type="text" name="foo" /> <!-- several of those here -->  
</form>
<form id="deleteForm" action="/post/dispatch/delete" method="post">
    <input type="hidden" value="some_id" />
</form>
<div id="toolbar">
    <input type="submit" name="save" value="Save" form="saveForm" />
    <input type="submit" name="delete" value="Delete" form="deleteForm" />
    <a href="/home/index">Cancel</a>
</div>

Эта опция довольно гибкая, но в оригинальном сообщении также упоминалось, что может потребоваться выполнить различные действия с одной формой. HTML5 снова приходит на помощь. Вы можете использовать атрибут formaction на кнопках отправки, чтобы разные кнопки в одной форме могли отправлять разные URL-адреса. В этом примере просто добавляется метод клонирования на панель инструментов вне формы, но он будет работать так же, как вложенный в форму.

<div id="toolbar">
    <input type="submit" name="clone" value="Clone" form="saveForm"
           formaction="/post/dispatch/clone" />
</div>

http://www.whatwg.org/specs/web-apps/current-work/#attributes-for-form-submission

Преимущество этих новых функций заключается в том, что они делают все это декларативно без JavaScript. Недостатком является то, что они не поддерживаются в старых браузерах, поэтому вам придется выполнить некоторое заполнение для старых браузеров.

53 голосов
/ 28 февраля 2009

Я бы реализовал это в точности так, как вы описали: отправьте все на сервер и выполните простой if / else, чтобы проверить, какая кнопка была нажата.

И тогда я реализовал бы вызов Javascript, привязанный к событию onsubmit формы, который проверял бы перед отправкой формы и передавал только соответствующие данные на сервер (возможно, через вторую форму на странице с идентификатором, необходимым для обработки). вещь как скрытый ввод, или обновите местоположение страницы с данными, которые вам нужно передать как запрос GET, или отправьте сообщение Ajax на сервер, или ...).

Таким образом, люди без Javascript могут нормально использовать форму, но нагрузка на сервер компенсируется, потому что люди, у которых есть Javascript, представляют только один необходимый фрагмент данных. Сосредоточение внимания только на поддержке одного или другого действительно ограничивает ваши возможности без необходимости.

В качестве альтернативы, если вы работаете за корпоративным брандмауэром или чем-то еще, и у всех отключен Javascript, вы можете захотеть сделать две формы и поработать с CSS-магией, чтобы создать вид, что кнопка удаления является частью первой формы. 1007 *

16 голосов
/ 28 февраля 2009

вы можете иметь формы рядом на странице, но не вложенные. затем использовать CSS, чтобы все кнопки выстроились в ряд довольно?

<form method="post" action="delete_processing_page">
   <input type="hidden" name="id" value="foo" />
   <input type="submit" value="delete" class="css_makes_me_pretty" />
</form>

<form method="post" action="add_edit_processing_page">
   <input type="text" name="foo1"  />
   <input type="text" name="foo2"  />
   <input type="text" name="foo3"  />
   ...
   <input type="submit" value="post/edit" class="css_makes_me_pretty" />
</form>
13 голосов
/ 14 мая 2010

HTML5 имеет представление о «владельце формы» - атрибуте «форма» для элементов ввода. Это позволяет эмулировать вложенные формы и решит проблему.

11 голосов
/ 06 декабря 2012

Вид старой темы, но эта может быть кому-то полезна:

Как кто-то упоминал выше - вы можете использовать пустышку. Мне пришлось преодолеть эту проблему некоторое время назад. Сначала я полностью забыл об этом HTML-ограничении и просто добавил вложенные формы. Результат оказался интересным - я потерял свою первую форму из вложенного. Тогда оказалось, что это своего рода «хитрость» - просто добавить фиктивную форму (которая будет удалена из браузера) перед фактическими вложенными формами.

В моем случае это выглядит так:

<form id="Main">
  <form></form> <!--this is the dummy one-->
  <input...><form id="Nested 1> ... </form>
  <input...><form id="Nested 1> ... </form>
  <input...><form id="Nested 1> ... </form>
  <input...><form id="Nested 1> ... </form>
  ......
</form>

Прекрасно работает с Chrome, FireFox и Safari. IE до 9 (не уверен около 10) и Opera не определяет параметры в основной форме. Глобальное $ _REQUEST пусто, независимо от входных данных. Внутренние формы, кажется, работают хорошо везде.

Не проверялось другое предложение, описанное здесь - набор полей вокруг вложенных форм.

РЕДАКТИРОВАТЬ : Frameset не работает! Я просто добавил основную форму после других (не больше вложенных форм) и использовал «клон» jQuery для дублирования входных данных в форме при нажатии кнопки. Добавлен .hide () к каждому из клонированных входов, чтобы сохранить макет без изменений, и теперь он работает как шарм.

4 голосов
/ 01 марта 2009

Я думаю, что Джейсон прав. Если ваше действие «Удалить» является минимальным, сделайте так, чтобы оно было в форме, и выровняйте его с другими кнопками, чтобы интерфейс выглядел как одна унифицированная форма, даже если это не так.

Или, конечно, перепроектировать ваш интерфейс, и позволить людям полностью удалить где-то еще, что не требует от них вообще видеть enormo-форму.

2 голосов
/ 28 февраля 2009

Один из способов сделать это без javascript - добавить набор переключателей, определяющих действие, которое необходимо выполнить:

  • Обновление
  • Удалить
  • Независимо от

Тогда скрипт действия будет выполнять различные действия в зависимости от значения установленного переключателя.

Другим способом было бы разместить на странице две формы, как вы предлагали, только не вложенные. Хотя макет может быть трудно контролировать, хотя:

<form name="editform" action="the_action_url"  method="post">
   <input type="hidden" name="task" value="update" />
   <input type="text" name="foo" />
   <input type="submit" name="save" value="Save" />
</form>

<form name="delform" action="the_action_url"  method="post">
   <input type="hidden" name="task" value="delete" />
   <input type="hidden" name="post_id" value="5" />
   <input type="submit" name="delete" value="Delete" />
</form>

Использование скрытого поля «задача» в скрипте обработки для соответствующего ветвления.

1 голос
/ 20 марта 2014

Эта дискуссия по-прежнему интересует меня. За исходным постом стоят «требования», которые, по-видимому, разделяет ФП - то есть форма с обратной совместимостью. Как человек, чья работа на момент написания статьи иногда должна поддерживать IE6 (и на годы вперед), я копаю это.

Не продвигая структуру (все организации захотят убедиться в совместимости / надежности, и я не использую это обсуждение в качестве обоснования для структуры), решения Drupal для этой проблемы интересны. Drupal также имеет прямое отношение, потому что у фреймворка давно существует политика «она должна работать без Javascript (только если вы хотите)», то есть проблема OP.

Drupal использует довольно обширные функции form.inc для поиска triggering_element (да, это имя в коде). См. Нижнюю часть кода, указанного на странице API, для form_builder (если вы хотите вникнуть в детали, рекомендуется использовать источник - drupal-x.xx / includes / form.inc ). Построитель использует автоматическую генерацию HTML-атрибута и, таким образом, может при возврате определить, какая кнопка была нажата, и действовать соответствующим образом (их можно настроить для запуска отдельных процессов).

Помимо конструктора форм, Drupal разделяет действия по удалению данных на отдельные URL / формы, вероятно, по причинам, указанным в исходном посте. Для этого требуется какой-то шаг поиска / перечисления ( стон другая форма !, но удобный для пользователя) в качестве предварительного. Но это имеет то преимущество, что устраняет проблему «отправить все». Большая форма с данными используется по назначению, для создания / обновления данных (или даже для действия «слияния»).

Другими словами, один из способов решения проблемы состоит в разделении формы на две части, после чего проблема исчезает (и методы HTML также могут быть исправлены с помощью POST).

1 голос
/ 24 марта 2013

Мое решение состоит в том, чтобы кнопки вызывали функции JS, которые пишут, а затем отправляют формы из основной формы

<head>
<script>
function removeMe(A, B){
        document.write('<form name="removeForm" method="POST" action="Delete.php">');
        document.write('<input type="hidden" name="customerID" value="' + A + '">');
        document.write('<input type="hidden" name="productID" value="' + B + '">');
        document.write('</form>');
        document.removeForm.submit();
}
function insertMe(A, B){
        document.write('<form name="insertForm" method="POST" action="Insert.php">');
        document.write('<input type="hidden" name="customerID" value="' + A + '">');
        document.write('<input type="hidden" name="productID" value="' + B + '">');
        document.write('</form>');
        document.insertForm.submit();
}
</script>
</head>

<body>
<form method="POST" action="main_form_purpose_page.php">

<input type="button" name="remove" Value="Remove" onclick="removeMe('$customerID','$productID')">
<input type="button" name="insert" Value="Insert" onclick="insertMe('$customerID','$productID')">

<input type="submit" name="submit" value="Submit">
</form>
</body>
1 голос
/ 05 марта 2011

Используйте iframe для вложенной формы. Если им нужно разделить поля, тогда ... это не совсем вложено.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...