Форма внутри формы
Доброго времени суток, господа. Помогите реализовать задуманное.
Есть Код JS $(function() { $("#form_status_added").click(function () { var elemCount = document.getElementsByClassName('param').length + 1; $("<div class='param mt-3'><div class='row'><div class='col-12'><div class='alert alert-primary text-center' id='totals'><strong>"+elemCount+"</strong></div></div><div class='col-12'><textarea rows='5' class='form-control mb-3' type='text' name='rabota"+elemCount+"[]' placeholder='Наименование видов работ'></textarea></div></div></div><div class='row'><div class='col-12 mb-2 text-center'><strong>Материал</strong></div></div><div class='row' id='mater"+elemCount+"'><div class='col-8'><input class='form-control mb-3' type='text' name='mater_name"+elemCount+"[]' placeholder='Название'></div><div class='col-2'><input class='form-control mb-3' type='text' name='mater_units"+elemCount+"[]' placeholder='Количество'></div><div class='col-2'><input class='form-control mb-3' type='text' name='mater_price"+elemCount+"[]' placeholder='Цена за ед.'></div></div><div class='row' id='nextmater"+elemCount+"'><div class='col-12'><input class='btn btn-primary btn-lg btn-block' type='button' value='Добавить Материал' id='form_"+elemCount+"'></div></div><div class='row'><div class='col-12'><hr></div></div>" ).insertBefore("#next"); document.getElementById('total').value = elemCount; }); }); $(function() { $("form_1").click(function () { $("<div class='row' id='mater1'><div class='col-8'><input class='form-control mb-3' type='text' name='mater_name1[]' placeholder='Название'></div><div class='col-2'><input class='form-control mb-3' type='text' name='mater_units1[]' placeholder='Количество'></div><div class='col-2'><input class='form-control mb-3' type='text' name='mater_price1[]' placeholder='Цена за ед.'></div></div>" ).insertBefore("#nextmater1"); }); }); $(document).ready(function () { var elemtotal = document.getElementsByClassName('param').length; document.getElementById('total').value = elemtotal; }); Код HTML <div class="param mt-3"> <div class="row"> <div class="col-12"><div class="alert alert-primary text-center" id="totals"><strong>1</strong></div></div> <div class="col-12"><textarea rows="5" class="form-control mb-3" type="text" name="rabota1[]" placeholder="Наименование видов работ"></textarea></div> </div> <div class="row"> <div class="col-12 mb-2 text-center"><strong>Материал</strong></div> </div> <div class="row" id="smeta_mater1"> <div class="col-8"><input class="form-control mb-3" type="text" name="smeta_mater_name1[]" placeholder="Название"></div> <div class="col-2"><input class="form-control mb-3" type="text" name="smeta_mater_units1[]" placeholder="Количество"></div> <div class="col-2"><input class="form-control mb-3" type="text" name="smeta_mater_price1[]" placeholder="Цена за ед."></div> </div> <div class="row" id="nextmater1"> <div class="col-12"> <input id="form_1" class="btn btn-primary btn-lg btn-block" type="button" value="Добавить Материал"> </div> </div> <div class="row"><div class="col-12"><hr></div></div> </div> <div class="row" id="next"> <div class="col-6"> <input class="btn btn-primary btn-lg btn-block" type="button" value="Добавить поле" id="form_status_added"> </div> <div class="col-6"> <input type="hidden" name="total" id="total" value=""> <button name="updates" class="btn btn-primary btn-lg btn-block">Обновить</button> </div> </div> Так вот. Это добавление внутри добавления. Примерно визуализированное https://jsfiddle.net/069fojyx/ Не работает #form_1 И как написать скрипт для всего добавленного по полю #form_status_added |
Цитата:
|
"#form_1" заработало
Я новичок в этой теме и неспеша разбираюсь при добавлении основного дополнительного поля все добавляется с уникальным индификатором, но дальше добавления не работает, даже с этим $(function() { $("#form_1").click(function () { $("<div class='row' id='smeta_mater1'><div class='col-8'><input class='form-control mb-3' type='text' name='smeta_mater_name1[]' placeholder='Название'></div><div class='col-2'><input class='form-control mb-3' type='text' name='smeta_mater_units1[]' placeholder='Количество'></div><div class='col-2'><input class='form-control mb-3' type='text' name='smeta_mater_price1[]' placeholder='Цена за ед.'></div></div>" ).insertBefore("#nextmater1"); }); }); $(function() { $("#form_2").click(function () { $("<div class='row' id='smeta_mater2'><div class='col-8'><input class='form-control mb-3' type='text' name='smeta_mater_name2[]' placeholder='Название'></div><div class='col-2'><input class='form-control mb-3' type='text' name='smeta_mater_units2[]' placeholder='Количество'></div><div class='col-2'><input class='form-control mb-3' type='text' name='smeta_mater_price2[]' placeholder='Цена за ед.'></div></div>" ).insertBefore("#nextmater2"); }); }); И чем отличается ID и CLASS у JS ? |
Цитата:
Использовать разные ID можно, но только не для такого: $("#form_1").click(function () ... $("#form_2").click(function () ... ... ибо это расточительство. Используя имя класса можно получить коллекцию элементов, то есть установить единый обработчик для всех элементов. А в случае их динамического добавления на страницу, делегировать обработчик ближайшему их общему родителю, который гарантированно присутствует на странице. В jQuery это так: $("селектор родителя").on("событие", "селектор элементов делегирующих обработку, имя их класса и т.п.", function() { //здесь this, это источник события, то есть элемент по которому щелкнули и т.п. //если им оперировать далее как jq-объектом, то это будет $(this) }} |
Так? (пока не работает)
<div class="row"> <div class="col-12 smeta_mater"> <div class="row smeta_list"> <div class="col-8"><input class="form-control mb-3" type="text" name="smeta_mater_name1[]" placeholder="Название"></div> <div class="col-2"><input class="form-control mb-3" type="text" name="smeta_mater_units1[]" placeholder="Количество"></div> <div class="col-2"><input class="form-control mb-3" type="text" name="smeta_mater_price1[]" placeholder="Цена за ед."></div> </div> </div> </div> </div> <div class="row"> <div class="col-12"> <input id="addmater" class="btn btn-primary btn-lg btn-block" type="button" value="Добавить Материал"> </div> </div> $(".param").on('click', '#addmater', function() { var list = ('.smeta_mater'); item = list.find('.smeta_list').last().clone(); item.find('input').val(''); list.append( item ); }); |
Если кнопка id="addmater" всегда на странице и ею производится добавление, то зачем делегировать ее события родителю? Вы ведь до этого совсем иное показывали, добавляя блоки, по которым нужно было щелкать, вот тогда и нужно было делегировать обработку.
А в данном примере, это просто обработчик щелчков по кнопке, копировать всегда первый дочерний блок DIV (тут даже и класса не нужно) родителя div.smeta_mater, который удалить нельзя, в отличие от добавляемых, возможность удаления которых в общем-то нужна. $("#addmater").click(function() { var list = ('div.smeta_mater'); list.children().first().clone().appendTo(list).find('input').val(''); //item.find('input').val(''); - а так будут возвращены поля, и только они будут вставлены //если так поступать, тогда item.find('input').val('').end(); и затем вставлять }); |
Все равно не могу понять
Есть div c class='param' ( первый блок с индификатором 1 ) В нем есть еще одна группа в обертке div с class='mater1' в котором есть div с class='list1' который нужно дублировать по кнопке с id='addmater1' Нажимая по кнопке с id='form_status_added' добавляется новый div c class='param' ( уже с индификатором 2 ) и у всех остальных тоже он 2 ( mater2 list2 addmater2 https://jsfiddle.net/2v4gnbL5/ Я никак не пойму как мне дописать код чтоб все работало Пробую разобраться но не понимаю |
Во-первых - texarea, это и есть текстовое поле и в отличие от input оно по определению своему не нуждается в указании type="text", и что это ненужный для него атрибут укажет даже редактор подсветкой.
Во-вторых - пора бы понять, что действиями типа name='rabota"+elemCount+"[]' и т.п., результатом которых сервер получит ключ плюс их нумерацию, вы заставляете сервер заниматься пустой и бесполезной работой. Эти действия кроме вредительства ничего не дают ни клиенту, ни серверу. Именовать поля нужно как fieldname[], без всяких номеров, и сервер получит массив с ключом fieldname с индексами от 0 до ... Тоже самое касается и class='mater1', и id='addmater1' и прочей пустой и никчемной нумерации. В третьих - в обработчике $("#form_status_added").click(function ... достаточно клонировать первый дочерний элемент формы, вставляя его перед $(this).closest('.row'). В четвертых - не знаю куда вставлять добавления по кнопке addmater, но как было сказано выше, выбросить и нумерацию и вообще ID у этой кнопки, вместо него добавьте этой кнопке какой либо класс, пусть к примеру это будет added. По имени этого класса делегировать обработку этих кнопок форме, как это делается было показано ранее. |
А зачем вам дублировать содержимое? Вы можете использовать уже прописанный в HTML код как шаблон для создания последующих частей!
Вот код, который добавляет материалы и поля! https://jsfiddle.net/ga5sw7fu/ Почистите код от лишних классов и <div>-ов! |
Malleys, только именовать поля нужно так:
rabota[0] mater_name[0][] mater_units[0][] mater_price[0][] и в обработчике form_status_added увеличивать индекс. Я так понимаю он хочет сгруппировать наборы. Вот только, по идее, должна быть возможность и удаления добавленного, а значит надо следить за всеми наборами, чтобы не получить дубликата ключа. |
Цитата:
В спецификации HTML5 сказано, что нет никаких ограничений на имена, которые можете использовать в атрибуте класса, однако рекомендуется использовать значения, которые описывают сущность/природу содержимого, а не такие значения, которые описывают желаемое представление контента.(https://www.w3.org/TR/html52/dom.htm...f-global-class) Т. е. в том примере с Bootstrap лучше так не делать, хотя можно. Например, лучше <div class="material-totals"></div>, а не <div class="alert alert-primary text-center" id="totals"><strong>1</strong></div></div> Также настоятельно рекомендуется рассматривать элемент <div> как крайнюю меру, когда уже никакой другой элемент не подходит. Использование более подходящих элементов вместо элемента <div> обеспечивает лучшую доступность и код, который легче поддерживать. (https://www.w3.org/TR/html52/groupin...he-div-element) |
Цитата:
|
Вроде все получилось, но почему то выскакивает ошибка
Uncaught TypeError: Cannot set property 'textContent' of null и Uncaught TypeError: Cannot set property 'name' of null Переделал этот код <form action="#" method="POST" class="form-horizontal"> <div class="param mt-3"> <div class="row"> <div class="col-12"><div class="alert alert-primary text-center" id="totals"><strong>1</strong></div></div> <div class="col-12"><textarea rows="5" class="form-control mb-3 rabota" type="text" name="rabota1" placeholder="Наименование видов работ"></textarea></div> </div> <div class="row"> <div class="col-12 mb-2 text-center"><strong>Материал</strong></div> </div> <div class="row"> <div class="col-12 mater"> <div class="row list" id="material_row"> <div class="col-8"><input class="form-control mb-3 mater_name" type="text" name="mater_name1[]" placeholder="Название"></div> <div class="col-2"><input class="form-control mb-3 mater_units" type="text" name="mater_units1[]" placeholder="Количество"></div> <div class="col-2"><input class="form-control mb-3 mater_price" type="text" name="mater_price1[]" placeholder="Цена за ед."></div> </div> </div> </div> <div class="row"> <div class="col-12"> <input id="add_material" class="btn btn-primary btn-lg btn-block" type="button" value="Добавить Материал"> </div> </div> <div class="row"><div class="col-12"><hr></div></div> </div> <div class="row" id="next"> <div class="col-6"> <input class="btn btn-primary btn-lg btn-block" type="button" value="Добавить поле" id="form_status_added"> </div> <div class="col-6"> <button name="updates" class="btn btn-primary btn-lg btn-block">Обновить</button> </div> </div> </form> var template = document.querySelector(".param").cloneNode(true); addEventListener("click", ({ target }) => { switch(target.id) { case "form_status_added": var elemCount = document.querySelectorAll(".param").length + 1; var node = template.cloneNode(true); node.querySelector("#totals").textContent = elemCount; node.querySelector(".rabota").name = "rabota"+elemCount; node.querySelector(".mater_name").name = "mater_name"+elemCount+"[]"; node.querySelector(".mater_units").name = "mater_name"+elemCount+"[]"; node.querySelector(".mater_price").name = "mater_name"+elemCount+"[]"; document.querySelector("#next").before(node); break; case "add_material": var node = target.closest(".param").querySelector("#material_row:last-of-type"); node.after(node.cloneNode(true)); break; } }); И перенеся на сайт мне выдает ошибку ?m=edit:148 Uncaught TypeError: Cannot read property 'cloneNode' of null at ?m=edit:148 и ничего не работает |
eLDeR, используйте jQuery коли он у вас и так есть, и вы в нем что-то можете. А этот код в общем-то не полный, в нем нет очистки значений клонируемых полей. А именование как было неудобным (querySelector(".rabota").name = "rabota"+elemCount), так и осталось. А именование других полей приведет к тому, что у вас наборы добавляемых полей (материалы) не будут соответствовать индексам добавляемых блоков (полей).
Ну возьмите простой php код, поместите в него форму с таким именованием полей и отправьте ее, чтобы убедится в том, что вы получите массив неудобный для обработки. |
Цитата:
|
Цитата:
Может хватит пустым красноречием заниматься? ;) |
Цитата:
Цитата:
|
Цитата:
Так к чему выпендриваться, да еще предлагать React? Или вы это для меня его сватаете? Да нехрен мне он нужен, мне заняться больше нечем, как разводить демагогию что лучше, а что хуже. |
Цитата:
Цитата:
eLDeR, Цитата:
Вот тоже самое, но при помощи React.js https://codepen.io/Malleys/pen/BeGBVL?editors=0010 Добавил удаление полей, материалов и сериализацию данных, вам только осталось написать реализацию отправки этих данных. (Сейчас выводит их в alert) |
Цитата:
|
Цитата:
Цитата:
Цитата:
Вот некоторые решения:
laimas, я не утверждаю, что эти решения самые правильные, их можно решить и другими способами... но эти решения учитывают, что человек может захотеть хранить данные формы в локальном хранилище, поскольку хочет, чтобы введённые данные не потерялись (позвонили, а потом когда вернулся на страницу, данные исчезли из-за того, что вкладка была выгружена, села батарейка и пр.), может захотеть иметь несколько таких форм на странице и т. д. Цитата:
Стоит однако отметить, что эта функция была очень полезна, когда вам нужно было, чтобы ваша программа работала и в IE тоже. Правда вместо того, чтобы предложить реализацию отсутствующих методов и функции в старых браузерах, jQuery была написана как нечто обособленное от DOM API, что привнесло однородность и путаницу в написании кода 13 лет назад, и совершенно не нужно сегодня, поскольку усложняет работу с Shadow DOM API, с наследованием (оно работает с багами), имеет свой собственный синтаксис селекторов, несовместимый со стандартом (вам придётся запутаться между двумя: jquery legacy и css, который работает, как в стилях, так и в DOM API), устаревшие методы jQuery (сегодня DOM API стандартизировано и работает одинаково во всех современных браузерах, во всяком случае вам придётся использовать новый функционал без jQuery, потому что он не поддерживает его!) Если вам нужна поддержка старых браузеров, то вы по прежнему можете писать стандартный и понятный код, подключив Polyfill Service. |
Часовой пояс GMT +3, время: 18:46. |