使用Mongoose和Node.js按用户所选分类加载产品的问题求解
问题原因
- 首次渲染页面时,你只给EJS模板传了
categories变量,没有传productCategory,模板渲染时找不到该变量直接抛出错误 - 你当前的逻辑是服务端单次渲染,用户在前端选择分类是客户端操作,没有触发服务端请求的情况下,无法动态加载对应分类的产品数据
- 你注释的代码逻辑存在两个问题:一是http请求只能返回一次响应,重复调用
res.render会报错;二是首次加载页面时用户还未选择分类,req.body.categoryName不存在,查询也会出错
修复步骤
1. 调整首次渲染的后端逻辑
首次加载页面时给productCategory传空数组,避免模板报错,修改后的makeABill方法如下:
exports.makeABill = (req, res, next) => { console.log('get Bill page'); categoryDB.find({}, function(err, data) { res.render('bill/makeABill.ejs', { categories: data, // 传空数组避免EJS找不到变量 productCategory: [] }); }); }
2. 新增产品查询接口
新增后端接口专门处理分类选完后的产品查询请求,代码如下:
// 新增接口:根据传入的分类名返回对应产品列表 exports.getProductsByCategory = (req, res, next) => { const selectedCategory = req.query.categoryName; // 注意findOne的查询条件要写为对象格式 categoryDB.findOne({categoryName: selectedCategory}, function(err, result) { // 返回空数组或者对应产品列表 res.json(result ? result.productsCategory : []); }); }
记得给该接口配置路由,示例路由规则:GET /api/get-products对应上面的方法。
3. 前端添加动态交互逻辑
在EJS页面底部添加JS代码,监听分类下拉框的选择事件,选中分类后发起请求获取对应产品,动态渲染产品下拉框:
<script> const categorySelect = document.getElementById('categoryName'); const productSelect = document.getElementById('productsCategory'); // 监听分类下拉框变化事件 categorySelect.addEventListener('change', async function() { const selected = this.value.trim(); // 未选中分类时清空产品下拉框 if (!selected) { productSelect.innerHTML = '<option value="">Select Product</option>'; return; } try { // 发起请求获取对应分类的产品列表 const resp = await fetch(`/api/get-products?categoryName=${encodeURIComponent(selected)}`); const productList = await resp.json(); // 渲染产品选项 let optionStr = '<option value="">Select Product</option>'; productList.forEach(product => { optionStr += `<option>${product}</option>`; }); productSelect.innerHTML = optionStr; } catch (e) { console.error('产品列表加载失败', e); } }) </script>
注意事项
- 如果你数据库存储的产品字段名和示例不同,渲染选项的时候自行替换对应字段即可
- 不要在同一个请求里多次调用
res.render,单次http请求只能返回一次响应
内容的提问来源于stack exchange,提问作者Hesham Eldawy
相关产品推荐
相关产品推荐

