WTForms与getElementById()未定义
我正在使用WTForms和JavaScript,想要创建一个表单,让用户可以在前端动态添加字段。我参考了这篇文章,了解了一些基本的做法。
https://sagarkaurav.hashnode.dev/flask-wtf-forms-dynamic-fields-using-javascript
现在我遇到的问题是,如何通过ID获取输入字段,并为新生成的输入字段创建唯一的ID。
当我在前端执行脚本时,document.getElementById('items-item')
返回的是未定义,而 identifyElement.getElementsByTagName('input')
返回的字段数量是正确的(1个)。代码执行到这里就停止了。未定义的结果让我觉得在代码执行时,HTML文档还没有创建好。我写了一个类似的JavaScript脚本,使用了window.onload来解决这个问题,但结果还是一样,我现在不明白为什么会这样,以及我缺少了什么。
app.py
class purchaseOrderFormSubClass(FlaskForm):
item = FieldList(StringField(''), min_entries=1, max_entries=99)
complete = FieldList(BooleanField(''), min_entries=1, max_entries=99)
ovp = FieldList(BooleanField(''), min_entries=1, max_entries=99)
instructions = FieldList(BooleanField(''), min_entries=1, max_entries=99)
class purchaseOrderForm(FlaskForm):
purchaseDate = DateField('Purchase Date', validators=[DataRequired()])
items = FormField(purchaseOrderFormSubClass)
@app.route('/create_purchase_order')
def create_purchase_order():
PurchaseOrderForm = purchaseOrderForm()
if PurchaseOrderForm.validate_on_submit():
return render_template('create_purchase_order.html', form=PurchaseOrderForm)
return render_template('create_purchase_order.html', form=PurchaseOrderForm)
create_purchase_order.html的模板
<div class="container">
<form method="POST" action="">
{{ form.csrf_token }}
{{form.purchaseDate.label}}
{{ form.purchaseDate(class_="form-control") }} <br>
<table class="table table-striped table-sm" id="table">
<thead>
<tr>
<th scope="col">TH1</th>
<th scope="col">TH2</th>
<th scope="col">TH3</th>
<th scope="col">TH4</th>
</tr>
</thead>
<tbody id="tableBody">
<tr>
{% for field in form.items%}
<td>
{{ field.hidden_tag }}
{{ field(class_='form-control') }}
</td>
{% endfor %}
</tr>
</tbody>
</table>
<button id="add-row" type="button" class="btn btn-primary">New Row onload</button>
<button type="button" class="btn btn-primary" onclick="addRow()">New Row onclick</button>
</form>
</div>
编辑
渲染后的HTML
<div class="container">
<form method="POST" action="">
<input id="csrf_token" name="csrf_token" type="hidden" value="ImU2NzVjZTY5ZWJlMDRlMzQzZmEwZWZlMjg4MTk5Y2RmMWNmOTFiMDIi.ZfDXXQ.NJc4fzGNyipMe5kyPuFhKk3zoss">
<label for="purchaseDate">Purchase Date</label>
<input class="form-control" id="purchaseDate" name="purchaseDate" required type="date" value=""> <br>
<table class="table table-striped table-sm" id="table">
<thead>
<tr>
<th scope="col">TH1</th>
<th scope="col">TH2</th>
<th scope="col">TH3</th>
<th scope="col">TH4</th>
</tr>
</thead>
<tbody id="tableBody">
<tr scope="row" class="align-middle">
<td>
<ul class="form-control" id="items-item"><li><label for="items-item-0"></label> <input id="items-item-0" name="items-item-0" type="text" value=""></li></ul>
</td>
<td>
<ul class="form-control" id="items-complete"><li><label for="items-complete-0"></label> <input id="items-complete-0" name="items-complete-0" type="checkbox" value="y"></li></ul>
</td>
<td>
<ul class="form-control" id="items-ovp"><li><label for="items-ovp-0"></label> <input id="items-ovp-0" name="items-ovp-0" type="checkbox" value="y"></li></ul>
</td>
<td>
<ul class="form-control" id="items-instructions"><li><label for="items-instructions-0"></label> <input id="items-instructions-0" name="items-instructions-0" type="checkbox" value="y"></li></ul>
</td>
<td>
<input class="form-control" id="items-csrf_token" name="items-csrf_token" type="hidden" value="ImU2NzVjZTY5ZWJlMDRlMzQzZmEwZWZlMjg4MTk5Y2RmMWNmOTFiMDIi.ZfDXXQ.NJc4fzGNyipMe5kyPuFhKk3zoss">
</td>
</tr>
</tbody>
</table>
<button id="add-row" type="button" class="btn btn-primary">New Row onload</button>
<button type="button" class="btn btn-primary" onclick="addRow()">New Row onclick</button>
</form>
</div>
JavaScript
function addRow() {
alert('clicked');
let tableBody = document.getElementById('tableBody');
let identifyElement = document.getElementById('items-item');
let countAllElements = identifyElement.getElementsByTagName('input');
let newRow = document.createElement('tr');
let identifyElementAlert = identifyElement.value;
let countAllElementsAlert = countAllElements.length;
alert(identifyElementAlert);
alert(countAllElementsAlert);
let newElementID = []
for(let i = 0; i = countAllElements.length; i++) {
newElementID.push(parseInt(countAllElements[i].name.split('-')[1]));
}
let newFieldName = `items-item${Math.max(...newElementID) + 1}`;
alert(newElementID);
alert(newFieldName);
newRow.innerHTML= `
<td>
<label for="${newFieldName}"></label> <input id="${newFieldName}" name="${newFieldName}" type="text" value="" class="form-control">
</td>
<td>
<label for="items-complete-0"></label> <input id="items-complete-0" name="items-complete-0" type="checkbox" value="y">
</td>
<td>
<label for="items-ovp-0"></label> <input id="items-ovp-0" name="items-ovp-0" type="checkbox" value="y">
</td>
<td>
<label for="items-instructions-0"></label> <input id="items-instructions-0" name="items-instructions-0" type="checkbox" value="y">
</td>
`;
tableBody.appendChild(newRow);
}
1 个回答
0
你的for循环里有个拼写错误。你不是在比较,而是给i
赋了一个新值。这样一来,当前的元素就找不到了,所以返回的是undefined
。
这里有一个你代码的替代版本。
function addRow() {
const elems = document.querySelectorAll('input[id^="items-item-"]');
if (elems.length) {
const elem = elems[elems.length-1],
tr0 = elem.closest('tr'),
tr1 = tr0.cloneNode(true)
Array.from(tr1.querySelectorAll('label[for^="items-"]')).forEach(label => {
const attr = label.getAttribute('for'),
input = tr1.querySelector(`input[name="${attr}"]`),
s = attr.replace(/items-(\w+)-(\d+)/, (match, p1, p2) => `items-${p1}-${parseInt(p2)+1}`);
label.setAttribute('for', s);
input.id = input.name = s;
})
tr0.parentNode.insertBefore(tr1, tr0.nextSibling);
}
}