英文:
how to render a page in node express from a route.post?
问题
以下是您要翻译的内容:
我有一个页面,从API中获取100个网络笑话。它在表格中显示这些网络笑话,每个笑话都有一个详情按钮,点击该按钮会将用户带到该笑话的详情页面。我必须对网络笑话路由执行POST请求,并渲染网络笑话的详情页面。POST请求成功,但是我的路由中的render()未渲染网络笑话页面。
Meme.js
```javascript
var express = require("express");
var router = express.Router();
var bodyParser = require("body-parser");
var jsonParser = bodyParser.json();
var ensureLogIn = require("connect-ensure-login").ensureLoggedIn;
var ensureLoggedIn = ensureLogIn();
router.post("/", ensureLoggedIn, jsonParser, (req, res, next) => {
const meme = req.body.meme;
const user = req.body.user;
try {
res.render("meme", { meme: meme, user: user });
} catch (error) {
console.error(error);
res.status(500).send("Internal Server Error");
}
});
module.exports = router;
memes.ejs按钮:
<tbody>
<% memes.forEach(meme=> { %>
<tr class="meme-row <%= viewedMemeIds.includes(meme.id) ? 'viewed' : '' %>" data-meme-id="<%= meme.id %>">
<td><img src="<%= meme.url %>" alt="<%= meme.name %>"></td>
<td>
<%= meme.name %>
</td>
<% if (user) { %>
<td>
<button class="btn-meme details-button" onclick="handleDetailsClick(<%= JSON.stringify(meme) %>, <%= JSON.stringify(user) %>)">Details</button>
</td>
<% } %>
</tr>
<% }) %>
</tbody>
MemeDetails.js:
async function handleDetailsClick(meme, user) {
try {
// 使用网络笑话和用户数据进行POST请求
const response = await fetch("/meme", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ meme, user }),
});
// 处理响应状态
if (!response.ok) {
throw new Error("网络响应不正确");
}
} catch (error) {
// 处理任何错误
console.error(error);
}
}
终端中的响应是:POST /meme 200 10.677 ms - 2703,但页面上没有渲染任何内容。
<details>
<summary>英文:</summary>
I have a page that fetches 100 memes from an api. it shows the memes in a table and each one has a details button that takes the user to a details page for the meme. I have to do a POST request to the meme route and render the meme details page. The post request is succesfull, but the meme page is not rendering from my render() in my router.post.
Meme.js
var express = require("express");
var router = express.Router();
var bodyParser = require("body-parser");
var jsonParser = bodyParser.json();
var ensureLogIn = require("connect-ensure-login").ensureLoggedIn;
var ensureLoggedIn = ensureLogIn();
router.post("/", ensureLoggedIn, jsonParser, (req, res, next) => {
const meme = req.body.meme;
const user = req.body.user;
try {
res.render("meme", { meme: meme, user: user });
} catch (error) {
console.error(error);
res.status(500).send("Internal Server Error");
}
});
module.exports = router;
memes.ejs button:
<tbody>
<% memes.forEach(meme=> { %>
<tr class="meme-row <%= viewedMemeIds.includes(meme.id) ? 'viewed' : '' %>" data-meme-id="<%= meme.id %>">
<td><img src="<%= meme.url %>" alt="<%= meme.name %>"></td>
<td>
<%= meme.name %>
</td>
<% if (user) { %>
<td>
<button class="btn-meme details-button" onclick="handleDetailsClick(<%= JSON.stringify(meme) %>, <%= JSON.stringify(user) %>)">Details</button>
</td>
<% } %>
</tr>
<% }) %>
</tbody>
MemeDetails.js:
async function handleDetailsClick(meme, user) {
try {
// Make a POST request to the meme route with the meme and user data
const response = await fetch("/meme", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ meme, user }),
});
// Handle the response status
if (!response.ok) {
throw new Error("Network response was not ok");
}
} catch (error) {
// Handle any errors
console.error(error);
}
}
response in terminal is: POST /meme 200 10.677 ms - 2703, but nothing renders on the page.
</details>
# 答案1
**得分**: 2
首先,我想提到关于 "但页面上什么都不渲染"。
它永远不会自动渲染页面,因为在 [MDN Webdocs][1] 中提到了 `fetch()` 用于通过 AJAX 调用从网络获取资源。您获取的资源将存储在 `response` 变量中,您需要手动处理获取的数据(无论是操作 DOM innerText 还是重定向到另一个页面,例如使用 `window.href.location`)。
但是,POST 请求通常用于在服务器上创建/修改数据(请阅读有关 [HTTP METHODS][2] 的内容)。我看到您使用 POST 请求来渲染页面/导航到另一个页面。GET 是用于从服务器请求数据的 HTTP 方法。
我认为更好的方法是改变您处理 `handleDetailsClick` 的方式。而不是传递整个 Meme 数据,您可以在 GET 方法的查询字符串中使用 Meme ID,例如使用 HTML 元素像 `<a href=".../meme?id=<%= meme.id %>">`,或者简单地修改 `<button>` 元素的 `onclick` 行为为 `window.location.href=".../meme?id=<%= meme.id %>"`。
然后,在 Express 侧,您可以将 POST 路由修改为 GET,并从查询字符串中获取特定的 ID,以便可以从数据库等位置搜索它,并使用 `res.render()` 渲染页面,就像下面的示例一样。
```javascript
app.get("/meme", function (req, res) {
const memeID = req.query.id;
// 从数据库或其他数据源使用指定的 ID 获取 Meme 详情
const memeDetails = db.findById(memeID);
res.render("pages/meme", { memeDetails });
});
希望这有所帮助。
更新
正如您提到的关于作业要求,您可以对上面的代码稍作修改(根据作业要求只使用ID或整个数据),而不是使用 res.render()
来渲染一个 HTML 页面,您可以简单地使用 res.JSON()
并利用 JS 使用 JSON 响应。
Meme.js
app.post("/meme", function (req, res) {
const memeID = req.body.id;
// 从数据库或其他数据源使用指定的 ID 获取 Meme 详情
const memeDetails = db.findById(memeID);
res.json({
success: true,
data: {
id : memeDetails.id,
name: memeDetails.name,
url : memeDetails.url,
}
})
});
meme.ejs(您可以放置任何将用作选定详细信息 Meme 容器的元素)
<table>
<tbody>
<% memes.forEach(meme=> { %>
<tr class="meme-row <%= viewedMemeIds.includes(meme.id) ? 'viewed' : '' %>" data-meme-id="<%= meme.id %>">
<td><img src="<%= meme.url %>" alt="<%= meme.name %>"></td>
<td>
<%= meme.name %>
</td>
<% if (user) { %>
<td>
<button class="btn-meme details-button" onclick="handleDetailsClick(<%= meme.id %>)">Details</button>
</td>
<% } %>
</tr>
<% }) %>
</tbody>
</table>
<div id="selectedMeme"></div>
然后对于 MemeDetails.js
async function handleDetailsClick(id) {
try {
// 使用 Meme id 发送 POST 请求到 meme 路由
const response = await fetch("/meme", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ id }),
});
// 处理响应状态
if (!response.ok) {
throw new Error("Network response was not ok");
}
// 处理响应(转换为 JSON 并利用它)
const jsonResp = await response.json();
if (!jsonResp.success) {
throw new Error("Something is error");
}
// 将获取的数据放入 HTML
const memeData = jsonResp.data;
document.getElementById('selectedMeme').innerHTML = `
<b>Meme name: ${memeData.name}</b>
<br />Meme url: <a href="${memeData.url}">Click me</a>
`;
} catch (error) {
// 处理任何错误
console.error(error);
document.getElementById('selectedMeme').innerHTML = '';
}
}
英文:
firstly I want to mention about "but nothing renders on the page".
It will never render the page automatically since it's mentioned in the MDN Webdocs that fetch()
is used for fetch resources from network using AJAX calls. The resources you've fetched will be stored on response
variable and you need to manually process the fetched data (whether manipulating the DOM innerText or redirect to another page e.g using window.href.location
)
But, POST request normally used for create/modify data on the server (please read about HTTP METHODS). I saw you use the POST request to render a page / navigating to another page. GET is the HTTP method that is used to request data from server.
I think it's better for you to change the way you handle the handleDetailsClick
. Instead of passing the whole meme data, you can use the meme ID in the query string of GET method using HTML element like <a href=".../meme?id=<%= meme.id %>">
or simply modify the onclick
behavior of <button>
element to have window.location.href=".../meme?id=<%= meme.id %>"
Then, in the express side you can modify the POST route to GET and get the specific ID in query string, so you can search it from database etc and render the page using res.render()
like in the example below.
<!-- begin snippet: js hide: false console: false babel: false -->
<!-- language: lang-js -->
app.get("/meme", function (req, res) {
const memeID = req.query.id;
// Fetch the meme details from DB or any other data sources using the specified ID
const memeDetails = db.findById(memeID);
res.render("pages/meme", { memeDetails });
});
<!-- end snippet -->
Hope it helps
Updated
As you mentioned about the requirement of assignment, you can modify a bit the above code for the POST route (you can use only ID or the whole data depend on the assignment requirement), instead of using res.render()
to render an html page, you can simply use res.JSON()
and utilize the JSON response using JS.
Meme.js
<!-- begin snippet: js hide: false console: false babel: false -->
<!-- language: lang-js -->
app.post("/meme", function (req, res) {
const memeID = req.body.id;
// Fetch the meme details from DB or any other data sources using the specified ID
const memeDetails = db.findById(memeID);
res.json({
success: true,
data: {
id : memeDetails.id,
name: memeDetails.name,
url : memeDetails.url,
}
})
});
<!-- end snippet -->
meme.ejs (you can put any element that will be a container for selected details meme)
<!-- begin snippet: js hide: false console: false babel: false -->
<!-- language: lang-html -->
<table>
<tbody>
<% memes.forEach(meme=> { %>
<tr class="meme-row <%= viewedMemeIds.includes(meme.id) ? 'viewed' : '' %>" data-meme-id="<%= meme.id %>">
<td><img src="<%= meme.url %>" alt="<%= meme.name %>"></td>
<td>
<%= meme.name %>
</td>
<% if (user) { %>
<td>
<button class="btn-meme details-button" onclick="handleDetailsClick(<%= meme.id %>)">Details</button>
</td>
<% } %>
</tr>
<% }) %>
</tbody>
</table>
<div id="selectedMeme"></div>
<!-- end snippet -->
then for the MemeDetails.js
<!-- begin snippet: js hide: false console: false babel: false -->
<!-- language: lang-js -->
async function handleDetailsClick(id) {
try {
// Make a POST request to the meme route with the meme id
const response = await fetch("/meme", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: { id },
});
// Handle the response status
if (!response.ok) {
throw new Error("Network response was not ok");
}
// Handle the response (convert to JSON and utilize it)
const jsonResp = await response.json();
if (!jsonResp.success) {
throw new Error("Something is error");
}
// put the fetched data to HTML
const memeData = jsonResp.data;
document.getElementById('selectedMeme').innerHTML = `
<b>Meme name: ${memeData.name}</b>
<br />Meme url: <a href="${memeData.url}">Click me</a>
`;
} catch (error) {
// Handle any errors
console.error(error);
document.getElementById('selectedMeme').innerHTML = '';
}
}
<!-- end snippet -->
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论