WTForms与getElementById()未定义

0 投票
1 回答
51 浏览
提问于 2025-04-14 16:47

我正在使用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);
    }
}

撰写回答