You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Node.js+Express+Handlebars:如何通过下拉菜单更新表行全部字段?

解决选中库存编号后自动填充描述和售价的问题

你的核心需求是选中下拉菜单里的库存编号后,自动把对应库存的描述和售价填充到新增行的输入框里。原代码的问题在于下拉选项没有携带额外的库存数据,导致前端无法获取对应字段的值,以下是修正方案:

问题分析

  1. 下拉菜单的<option>只显示了partnr,没有存储对应的description和salesprice,所以updateFields函数无法拿到正确的填充值
  2. updateFields函数错误地使用selectedOption.text(也就是partnr)去填充描述和售价字段
  3. fetch_data函数逻辑冗余,重复给同一个select元素赋值,且返回的数据结构没有包含完整的库存信息

修正步骤

1. 修改后端接口,返回完整库存数据

在Express的/parts/get_stock接口里,返回包含itemnr、description、salesprice的完整对象:

// Express 后端示例
app.get('/parts/get_stock', async (req, res) => {
  try {
    // 查询STOCK表的完整数据
    const stockItems = await db.query('SELECT itemnr, description, salesprice FROM STOCK');
    res.json(stockItems.rows);
  } catch (err) {
    console.error(err);
    res.status(500).json({ error: 'Failed to fetch stock' });
  }
});

2. 修正前端下拉菜单的渲染逻辑

去掉冗余的{{#selected}}块,直接渲染所有库存选项,并把description和salesprice存在option的data-*属性里:

<!-- 替换原下拉菜单代码 -->
<select name="partnr" id="partnr" onchange="updateFields(this)" required> 
  <option value="">Select a part</option>
  {{#each stockItems}} 
    <option value="{{itemnr}}" data-description="{{description}}" data-salesprice="{{salesprice}}">
      {{itemnr}}
    </option>
  {{/each}}       
</select>

3. 修复updateFields函数

从选中的option的data属性里获取对应的描述和售价,填充到输入框:

function updateFields(selectElement) {
  const row = selectElement.closest('tr');
  const selectedOption = selectElement.options[selectElement.selectedIndex];
  
  // 从data属性获取对应值
  const description = selectedOption.dataset.description || '';
  const salesPrice = selectedOption.dataset.salesprice || '';
  
  // 填充到对应输入框
  row.querySelector('[name="description"]').value = description;
  row.querySelector('[name="sales_price"]').value = salesPrice;
}

4. 简化fetch_data函数(可选)

如果不需要动态加载库存(因为Handlebars已经渲染了stockItems),可以去掉自动加载逻辑;如果需要动态加载,修正后的函数如下:

function _(element) {
  return document.getElementById(element);
}

function fetch_data() {
  fetch('/parts/get_stock')
    .then(response => response.json())
    .then(stockItems => {
      const select = _('partnr');
      let html = '<option value="">Select a part</option>';
      stockItems.forEach(item => {
        html += `<option value="${item.itemnr}" data-description="${item.description}" data-salesprice="${item.salesprice}">
                  ${item.itemnr}
                </option>`;
      });
      select.innerHTML = html;
    })
    .catch(err => console.error('Failed to fetch stock:', err));
}

// 可选:如果需要聚焦时加载库存
// _('partnr').onfocus = fetch_data;

5. 修正新增表单的提交路径

原表单的action="/parts/addit/{{partnr}}"是静态值,改成后端从表单参数里获取partnr:

<!-- 修改新增表单 -->
<form action="/parts/addit" method="POST">
  <input type="hidden" name="job_nr" value="{{job_nr}}">
  <button type="submit">Add</button>
</form>

后端接口获取参数并插入数据:

app.post('/parts/addit', async (req, res) => {
  const { job_nr, partnr, description, quantity, sales_price } = req.body;
  // 插入到ITEMSUSED表
  await db.query(
    'INSERT INTO ITEMSUSED (itemnr, description, salesprice, quantity, job_nr) VALUES ($1, $2, $3, $4, $5)',
    [partnr, description, sales_price, quantity, job_nr]
  );
  res.redirect(`/jobs/updatejob/${job_nr}`);
});

完整修正后的前端代码

<div class="text-center">
  <h1 class="top-label">Spares Used for Job {{ thisjobnr }}</h1>
</div>

<div class="container text-center">
  <div class="top-menu">      
    <a href="/jobs/updatejob/{{ thisjobnr }}" class="btnGeneral">Back</a>  
  </div>      
</div>
<p></p>

<div style="overflow-x:auto;" >   
  <table class="table center">
    <thead>
      <tr> 
        <th class="tblabel th">Part Number</th> 
        <th class="tblabel th">Description</th>
        <th class="tblabel th">Quantity</th>
        <th class="tblabel th text-right">Sales Price</th>
        <th class="tblabel th text-right">Action</th>
      </tr>
    </thead>
    <tbody>
      {{#each rows}}
      <tr>
        <td class="tbtext td">{{partnr}}</td>
        <td class="tbtext td">{{description}}</td>
        <td class="tbtext td">{{quantity}}</td>
        <td class="tbtext td">{{sales_price}}</td>

        <td>
          <form action="/parts/delete/{{partnr}}" method="POST">
            <input type="hidden" name="job_nr" value="{{job_nr}}">
            <button type="submit">Delete</button>
          </form>
        </td>
      </tr>
      {{/each}}
      <tr>
        <td>
          <div class="select">
            <select name="partnr" id="partnr" onchange="updateFields(this)" required> 
              <option value="">Select a part</option>
              {{#each stockItems}} 
                <option value="{{itemnr}}" data-description="{{description}}" data-salesprice="{{salesprice}}">
                  {{itemnr}}
                </option>
              {{/each}}       
            </select> 
          </div>          
        </td>
        <td><input type="text" name="description" readonly></td>
        <td><input type="text" name="quantity" required></td>
        <td><input type="text" name="sales_price" readonly></td>
        <td>
          <form action="/parts/addit" method="POST">
            <input type="hidden" name="job_nr" value="{{job_nr}}">
            <button type="submit">Add</button>
          </form>
        </td>
      </tr>
    </tbody>
  </table>
</div>

<script>
function updateFields(selectElement) {
  const row = selectElement.closest('tr');
  const selectedOption = selectElement.options[selectElement.selectedIndex];
  
  const description = selectedOption.dataset.description || '';
  const salesPrice = selectedOption.dataset.salesprice || '';
  
  row.querySelector('[name="description"]').value = description;
  row.querySelector('[name="sales_price"]').value = salesPrice;
}
</script>

<script>
function _(element) {
  return document.getElementById(element);
}

function fetch_data() {
  fetch('/parts/get_stock')
    .then(response => response.json())
    .then(stockItems => {
      const select = _('partnr');
      let html = '<option value="">Select a part</option>';
      stockItems.forEach(item => {
        html += `<option value="${item.itemnr}" data-description="${item.description}" data-salesprice="${item.salesprice}">
                  ${item.itemnr}
                </option>`;
      });
      select.innerHTML = html;
    })
    .catch(err => console.error('Failed to fetch stock:', err));
}

// 可选:如果需要聚焦时加载库存
// _('partnr').onfocus = fetch_data;
</script>

内容的提问来源于stack exchange,提问作者Stef

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 16:59:50