Таргетинг на все метки внутри таблицы с использованием JavaScript
У меня есть следующие настройки. здесь я пытаюсь добавить пользовательские радио и флажки.
Array.from(document.querySelectorAll("tr")).forEach((tr,index)=>{
var mark=document.createElement("span");
Array.from(tr.querySelectorAll("input")).forEach((inp,index1)=>{
if(inp.type=="radio"){
mark.classList.add("dotmark");
inp.parentNode.appendChild(mark);
}
else{
mark.classList.add("checkmark");
inp.parentNode.appendChild(mark);//instead append in to the next td's label tag
}
})
})
span{
width:20px;
height:20px;
background:#ccc;
display:inline-block;
}
<table id="tab1" class="table labelCustom">
<tbody>
<tr><td><input type='radio' id='one' name='name'></td><td><label for='one'>example</label></td></tr>
<tr><td><input type='radio' id='two' name='name'></td><td><label for='two'>example</label></td></tr>
<tr><td><input type='radio' id='three' name='name'></td><td><label for='three'>example</label></td></tr>
</tbody>
</table>
Я хочу, чтобы элемент span, созданный динамически, был вставлен в тег label. сейчас он вставляет его во входы тд.
Примечание: класс элемента span зависит от типа ввода.
3 ответа
Одним из подходов среди многих является следующий:
Array.from(document.querySelectorAll("tr")).forEach((tr, index) => {
var mark = document.createElement("span");
Array.from(tr.querySelectorAll("input")).forEach((inp, index1) => {
// caching the <label> element for readability:
let label = inp.parentNode.nextElementSibling.querySelector('label');
// adding the class-name based on the result of the ternary operator,
// if the input.type is equal to 'radio' we return the class-name of
// 'dotmark', otherwise we return 'checkmark':
mark.classList.add(inp.type === 'radio' ? 'dotmark' : 'checkmark');
// appending the element held within the 'mark' variable:
label.appendChild(mark);
})
})
span {
width: 20px;
height: 20px;
background: #ccc;
display: inline-block;
}
span.dotmark {
background-color: limegreen;
}
span.checkmark {
background-color: #f90;
}
<table id="tab1" class="table labelCustom">
<tbody>
<tr>
<td><input type='radio' id='one' name='name'></td>
<td><label for='one'>example</label></td>
</tr>
<tr>
<td><input type='radio' id='two' name='name'></td>
<td><label for='two'>example</label></td>
</tr>
<tr>
<td><input type='radio' id='three' name='name'></td>
<td><label for='three'>example</label></td>
</tr>
<tr>
<td><input type='checkbox' id='four' name='differentName'></td>
<td><label for='four'>example</label></td>
</tr>
</tbody>
</table>
В качестве дополнения, от комментария ФП к вопросу:
Я старался
nextSibling
но это не сработало, ноnextSiblingElement
работал.
Разница между ними заключается в том, что nextSibling
возвращает любого брата, будь то текстовый узел, элементный узел или любой другой, тогда как nextElementSibling
, как следует из названия, возвращает следующего родного брата, который также является элементом-узлом.
Рекомендации:
Element.querySelector()
,Node.nextSibling
,NonDocumentTypeChildNode.nextElementSibling
,
Использование
inp.parentNode.nextElementSibling.querySelector('label')
вместо просто
inp.parentNode
Array.from(document.querySelectorAll("tr")).forEach((tr,index)=>{
var mark=document.createElement("span");
Array.from(tr.querySelectorAll("input")).forEach((inp,index1)=>{
if(inp.type=="radio"){
mark.classList.add("dotmark");
inp.parentNode.nextElementSibling.querySelector('label').appendChild(mark);
}
else{
mark.classList.add("checkmark");
inp.parentNode.nextElementSibling.querySelector('label').appendChild(mark);
}
})
})
span{
width:20px;
height:20px;
background:#ccc;
display:inline-block;
}
<table id="tab1" class="table labelCustom">
<tbody>
<tr><td><input type='radio' id='one' name='name'></td><td><label for='one'>example</label></td></tr>
<tr><td><input type='radio' id='two' name='name'></td><td><label for='two'>example</label></td></tr>
<tr><td><input type='radio' id='three' name='name'></td><td><label for='three'>example</label></td></tr>
</tbody>
</table>
Вам не нужны вложенные циклы, один раз для tr, а затем для ввода, так как у вас есть только один вход и метка внутри каждого tr, так что вы можете объединить их в один запрос как tr input
, И вам не нужно использовать Array.from
, поскольку querySelectorAll
возвращается NodeList
которые уже имеют forEach
функция.
document.querySelectorAll('tr input').forEach(input => {
const span = document.createElement('span')
span.classList.add(input.type === 'radio' ? 'dotmark' : 'checkmark')
input.parentNode.nextElementSibling.appendChild(span)
})