insertBefore для нескольких элементов работает только с последним

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

Итак, я пишу этот JavaScript:

var allInputs = document.querySelectorAll("input");  
var newItem = document.createElement("LI");  
var textnode = document.createTextNode("(*)");  
newItem.appendChild(textnode);  
for (var i = 0; i < allInputs.length; i++) {  
        if(allInputs[i].hasAttribute('required') == true){  
          allInputs[i].parentNode.insertBefore(newItem, allInputs[i]);  
        }  
}  

Результат: добавляется (*) только перед последним вводом. Я попытался запустить этот код в консоли браузера построчно и заметил, что он добавляет текст на ввод и стирает предыдущий.

Я не веб-разработчик и использую примеры, найденные в Интернете, поэтому для меня это сложно :/


person Marcos Antonio    schedule 15.06.2018    source источник


Ответы (3)


Вы создаете новый li только один раз, до начала цикла, поэтому каждый раз, когда вы insertBefore вы удаляете li из его предыдущего местоположения и помещаете его в новое место.

Если у нового элемента есть только один дочерний узел, и этот дочерний узел является текстовым узлом, проще просто присвоить textContent.

Вместо этого создайте новый li на каждой итерации:

const allInputs = document.querySelectorAll("input");
for (let i = 0; i < allInputs.length; i++) {  
  if(allInputs[i].hasAttribute('required') == true){  
    const newItem = document.createElement("LI");  
    newItem.textContent = '(*)';
    allInputs[i].parentNode.insertBefore(newItem, allInputs[i]);
  }  
}  
person CertainPerformance    schedule 15.06.2018

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

Используйте cloneNode(), чтобы создать новую копию вашего элемента. которые вы можете разместить в каждом месте.

allInputs[i].parentNode.insertBefore(newItem.cloneNode(true), allInputs[i]);  
person Patrick Evans    schedule 15.06.2018

Я не знаю, где вы хотите разместить свою отметку, но добавление ее в <li> приведет к тому, что отметка появится на новой строке.

Лично я бы добавил метку сбоку от ввода, вот так:

const allInputs = document.querySelectorAll("input[required]");
const addMark = x => x.parentNode.appendChild(document.createTextNode("*"));
[...allInputs].forEach(addMark);
<ul>
<li><label>First name <input required/></label>
<li><label>Second name <input/></label>
<li><label>Email<input type="email" required/></label>
<li><label>Information <input/></label>
</ul>

person Jorjon    schedule 15.06.2018