Лучший способ добавить дополнительную (вложенную) форму в середине формы с вкладками - PullRequest
12 голосов
/ 28 декабря 2010

У меня есть веб-приложение, состоящее в основном из большой формы с информацией. Форма разбита на несколько вкладок, чтобы сделать ее более читабельной для пользователя:

<form>
<div id="tabs">
  <ul>
    <li><a href="#tab1">Tab1</a></li>
    <li><a href="#tab2">Tab2</a></li>
  </ul>
  <div id="tab1">A big table with a lot of input rows</div>
  <div id="tab2">A big table with a lot of input rows</div>
</div>
</form>

Форма динамически расширяется (в таблицы добавляются дополнительные строки). Каждые 10 секунд форма сериализуется и синхронизируется с сервером.

Теперь я хочу добавить интерактивную форму на одной из вкладок: когда пользователь вводит имя в поле, эта информация отправляется на сервер и возвращается идентификатор, связанный с этим именем. Этот идентификатор используется в качестве идентификатора для некоторых динамически добавляемых полей формы.

Быстрый набросок такой страницы будет выглядеть так:

<form action="bigform.php">
<div id="tabs">
  <ul>
    <li><a href="#tab1">Tab1</a></li>
    <li><a href="#tab2">Tab2</a></li>
  </ul>
  <div id="tab1">A big table with a lot of input rows</div>
  <div id="tab2">
    <div class="associatedinfo">
    <p>Information for Joe</p>
    <ul>
      <li><input name="associated[26][]" /></li>
      <li><input name="associated[26][]" /></li>
    </ul>
    </div>

    <div class="associatedinfo">
    <p>Information for Jill</p>
    <ul>
      <li><input name="associated[12][]" /></li>
      <li><input name="associated[12][]" /></li>
    </ul>
    </div>
    <div id="newperson">
      <form action="newform.php">
        <p>Add another person:</p> 
        <input name="extra" /><input type="submit" value="Add" />
      </form>
    </div>
  </div>
</div>
</form>

Выше не будет работать: вложенные формы не допускаются в HTML. Однако мне действительно нужно отобразить форму на этой вкладке: это часть функциональности этой страницы. Мне также нужно поведение отдельной формы: когда пользователь нажимает кнопку возврата в поле формы, нажимается кнопка «Добавить» и на частичной форме запускается действие отправки.

Как лучше всего решить эту проблему?

Ответы [ 9 ]

10 голосов
/ 31 декабря 2010

Одна вещь, которую вы могли бы сделать, это вместо того, чтобы установить тип элемента ввода «Добавить» на «отправить», установить его на «кнопку» и добавить атрибут id для регистрации обработчика щелчков:

<!-- ... -->
    <div id="newperson">
      <p>Add another person:</p> 
      <input id="extra_input" name="extra" /><input id="add_button" type="button" value="Add" />
    </div>
<!-- ... -->

Причина типа ввода "кнопка" заключается в том, что получающаяся кнопка на странице выглядит точно так же, как кнопка отправки, но по умолчанию она ничего не делает при нажатии, что позволяет настраивать ее эффект. Кроме того, тип ввода «кнопка» поддерживается во всех браузерах, поддерживающих HTML 3.2 или более позднюю версию , включая HTML 5 .

.

Где-то в вашем Javascript у вас, вероятно, есть функция, которую вы хотите вызывать всякий раз, когда пользователь нажимает кнопку «Добавить». Предположим, что он называется addAnotherPerson, вы просто вызываете addAnotherPerson в обработчике кликов:

// This is jQuery code, but all JS frameworks that I have seen have a similar feature to register a click handler on a DOM element referenced by ID.
$("#add_button").click(function (event) {
    addAnotherPerson();
    $("#extra_input").val(""); // reset the value
});

Вам также необходимо добавить обработчик нажатия клавиш для «дополнительного» ввода текста, чтобы выполнить то же действие, когда пользователь нажимает клавишу Enter:

$("#extra_input").keydown(function (event) {
    if (event.keyCode == 0xa || event.keyCode == 0xd) {
        addAnotherPerson();
        $("#extra_input").val(""); // reset the value
    }
});

Обязательно добавьте атрибут autocomplete="off" для «дополнительного» ввода текста.

Функция addAnotherPerson может отправлять асинхронный запрос POST, содержащий значение в текстовом поле «extra», обновляя DOM впоследствии, если это необходимо.

РЕДАКТИРОВАТЬ: Если вы также хотите поддерживать пользователей, у которых отключен Javascript, добавьте атрибуты name к каждой кнопке отправки с уникальным значением атрибута name для каждого вашего серверного приложения. сможет сказать, на какую кнопку нажал пользователь.

Взять, к примеру, этот код из http://www.alanflavell.org.uk/www/trysub.html:

<table>
<tr><td align=left><label for="aquavit_button"><input id="aquavit_button" type="submit" name="aquavit" value="[O]"> Aquavit</label></td></tr>
<tr><td align=left><label for="beer_button"><input id="beer_button" type="submit" name="beer" value="[O]"> Beer</label></td></tr>
<tr><td align=left><label for="champagne_button"><input id="champagne_button" type="submit" name="champagne" value="[O]"> Champagne</label></td></tr>
<tr><td align=left><label for="water_button"><input id="water_button" type="submit" name="water" value="[O]"> Dihydrogen monoxide</label></td></tr>
</table>

Если пользователь нажимает кнопку «[O]» рядом с «Пивом», браузер отправляет переменную POST «beer», но не переменную POST «aquavit», «champagne» или «water». Попробуйте в http://www.alanflavell.org.uk/www/trysub.html.

Одна сложная проблема с этой техникой - это случай, когда пользователь отправляет форму, нажимая клавишу Enter при вводе текста. Firefox отправляет переменную POST для первой кнопки отправки в форме (в данном случае «aquavit»), тогда как Internet Explorer не отправляет переменную POST для любой из кнопок отправки. Вы можете исправить эту разницу, добавив скрытую, безымянную кнопку отправки в самом начале формы:

<form action="bigform.php"><input type="submit" style="display:none;" />
<!-- ... -->

EDIT2: Если вы всегда будете уверены, что значение в «дополнительном» текстовом вводе очищено Javascript перед отправкой большой формы, то вы сможете определить, есть ли у пользователя Javascript отключено и они нажимают клавишу Enter при вводе «лишнего» текста (указывая, что они хотят выполнить действие добавления человека), проверяя, не является ли «лишняя» переменная POST пустой на стороне сервера , Если он не пустой, вы можете предположить, что у пользователя отключен Javascript и что он хочет добавить пользователя.

Добавить этот код:

$("#bigform").submit(function (event) {
    $("#extra_input").val(""); // reset the value in the "extra" text input
    return true;
});
6 голосов
/ 06 января 2011

HTML должен быть семантическим, и его следует считать первым - т.е. он должен иметь четкую структуру и смысл без понимания того, что лежит на вершине javascript.Подобно тому, как <ul> должен содержать только <li> элементов, <form> должен иметь только одну цель.Использование javascript для улучшения формы путем извлечения динамических данных - это хорошо, но если используется дополнительный HTTP-запрос POST (тип, который изменяет данные на сервере), то это действительно представляет собой вторую цель, и, следовательно, вторуюФорма должна быть использована.Вторая форма со своим собственным атрибутом «action» сигнализирует о том, что здесь происходит определенное поведение, и она не только более концептуально обоснована, но и легче анализируется, отлаживается или расширяется при необходимости.

<form id="bigform" action="bigform.php">
    <!-- Tabs here -->
</form>
<form id="newperson" action="newform.php">
   <input name="extra">
   <button type="submit" value="Add">
   <!-- Note also the use of <button> instead of <input> -->
</form>

Важно то, что вы все еще можете достичь желаемого потока в основной форме. В основной форме вместо использования вложенной формы используйте <fieldset>.Этот набор полей будет вести себя как прокси для формы newperson.Входные данные внутри могут иметь идентификатор, но не должно иметь имени, поскольку его значение не предназначено для отправки в основной форме.Как уже упоминалось в других ответах, кнопка должна быть изменена на тип «кнопка», а не «отправить».

<form id="bigform" action="bigform.php">
    <!-- Tabs here -->
    <fieldset id="newpersonProxy">
        <input id="extra">
        <button type="button" value="Add">
    </fieldset>
</form>

Теперь добавьте желаемое поведение незаметно через Javascript , с помощью:

  1. Скрытие второй формы, #newperson.
  2. Реагирование на «отправку» путем привязки к событию keyup любого ввода в пределах #newpersonProxy, а также к щелчкусобытие кнопки.Для события keyup используйте event.which вместо event.keyCode, поскольку jQuery нормализует это.Вы хотите event.which == 13 для клавиши ввода.
  3. Затем скопировать значение из прокси-входов в реальную форму перед вызовом $("#newperson").submit().

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

Далее, поскольку функционирующий HTML рассматривался первым,простая подстройка может позволить формам работать без Javascript - просто скройте <fieldset> с помощью CSS и покажите его с помощью Javascript.Если Javascript отключен, вкладки будут разделены, вложенный набор полей будет скрыт, и будет отображена вторая форма (и полностью работоспособная, только не через AJAX).

2 голосов
/ 06 января 2011

Это не так многословно, как другие ответы, но ..

Это должно быть супер просто;)

  • Полностью избавьтесь от тегов FORM
  • Используйте jQuery для получения значений поля ввода
  • Когда пользователь щелкает элемент submit «a», который выглядит как кнопка отправки, он просто делает запрос ajax, фиксируя значения полей ввода.

Вот пример , который показывает бит форматирования, на которое я ссылаюсь, однако это сохраняет теги формы и является более старым примером, когда я использовал библиотеку scriptaculous. Вот JS , он демонстрирует немного структурирования.

Если вы +1 мне и даете мне знать, что вам нравится этот ответ, я разработаю функциональный пример для вас;)

Ура! Кирк

2 голосов
/ 31 декабря 2010

Что-то вроде следующего должно сделать это.

Если JavaScript отключен, вам нужно будет определить, нажал ли пользователь «Добавить» submitButton с помощью:

$_POST["submitButton"] == "Add"


    <!-- other stuff goes here -->

    <div id="newperson">
        <p>Add another person:</p> 
        <input name="extra" id="extra" /><input name="submitButton" id="addPerson" type="submit" value="Add" />
    </div>
  </div>
</div>
</form>
<script>
    var extra = $("#extra"),
        addPerson = $("#addPerson").click(function(e){
        // val would be the new person's name, e.g., "David"
        var val = extra.val();
        // you will want to give the user some AJAXy feedback here.

        $.post(this.form.action, {"extra": val}, function(response){
            // rest the extra div.
            extra.val("");

            /* 'response' could look like:                             */
            // <div class="associatedinfo">
            //      <p>Information for David</p>
            //      <ul>
            //        <li><input name="associated[13][]" /></li>
            //        <li><input name="associated[13][]" /></li>
            //      </ul>
            //   </div>
            $(response).insertBefore("#newperson");

            // or 'response' could be json data, or whatever. I have a feeling
            // you know enough about jQuery to handle the response-data.  :-)

        });
        // prevent it from bubbling up.
        e.preventDefault();
    });

    extra.keydown(function(e){
        // submit the new person's name via ajax if enter is pressed.
        if(e.keyCode === 13){
            addPerson.click();
            e.preventDefault();
        }
    });
</script>
1 голос
/ 07 января 2011

Вам не нужна вложенная форма, вы можете использовать другую форму (не вложенную) и использовать абсолютное позиционирование, чтобы разместить ее где угодно на странице. В любом случае все это создание динамических элементов управления с идентификатором, связанным с именем, введенным пользователями очень сложно ... возможно, у нас может быть более простое решение, если бы вы могли рассказать о бизнес-проблеме, которую вы пытаетесь решить.

1 голос
/ 07 января 2011

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

В противном случае другие предложения по отправке либо "внутренней" формы, либо всей формы через AJAX также могут работать.

1 голос
/ 31 декабря 2010

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

<form action="bigform.php">

    ....

    <div id="newperson">
      <p>Add another person:</p> 
      <input name="extra" /><button value="Add"/>
    </div>
  </div>
</div>
</form>
<div style='display:none;'>
    <form action="newform.php" id='add_person_form'>
      <input id='add_person_name' />
      <input type="submit" id='add_person_submit' />
    </form>
</div>

<script>
$('#newperson input').keyup(function(e) {
    if(e.keyCode == 13) submitNewPersonForm();
});
$('#newperson button').click(function(e) {
    submitNewPersonForm();
});

function submitNewPersonForm() {
    // copy the content from the placeholder form
    $('#add_person_name').val($("#newperson input").val());
    // submit this form
    $("#add_person_form").submit();
}
</script>

Это должно делать все, что вам нужно, сохраняя при этом исходную функциональность, насколько я могу судить.

Примечание: кнопка "Отправить" на самом деле не нужна в форме #add_person_form, я просто сохранил ее там, чтобы вы могли легко увидеть, куда я "переместил" вашу форму.

1 голос
/ 31 декабря 2010

Почему бы вам не вложить объекты формы и не обрабатывать ВСЕ действия в одном php-коде ...

# have this form appended to the DOM via ajax/js when a link is clicked
<div id="newperson">
  <p>Add another person:</p> 
  <input type="text" name="associated[new][]" />
</div>

Затем использовать php-логику в бэкэнде для создания ассоциации, если она "новая":

foreach($_POST['associated'] as $obj) {
  if($obj == "new")
    // create a new record
  else
    // do your other processing
}
0 голосов
/ 28 декабря 2010

Вы можете использовать ajax или создать другую форму за пределами первой и расположить ее, используя абсолютный слой DIV.

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

<form>

...
  <div style='height: 300px;' class='placeholder'> ... </div>
</form>

<form>...<form>

Вы отображаете вторую форму, где .placeholder равен

...