I have a page that gets 100 memes from an api. It displays memes in a table, and each meme has a details button that takes the user to the meme's details page. I have to perform a POST request to the meme route and render the meme details page. The post request is successful, but the meme page is not rendered from render() in 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.egs 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); } }
The response in the terminal is: POST /meme 200 10.677 ms - 2703, but nothing is rendered on the page.
P粉7187309562023-09-09 16:21:06
First I would like to mention "But nothing is rendered on the page".
It never automatically renders the page, as it is stated in MDN Webdocs that fetch()
is used to fetch resources from the network using AJAX calls. The resource you get will be stored in the response
variable and you will need to manually handle the fetched data (either manipulating the DOM insideText or redirecting to another page, e.g. using window.href.location< /代码>)
However, POST requests are typically used to create/modify data on the server (please read HTTP Methods). I see you are using POST request to render the page/navigate to another page. GET is the HTTP method used to request data from the server.
I think you'd better change the way you handle handleDetailsClick
. Instead of passing the entire meme data, you can use HTML elements such as Or simply modify the
element The
onclick
behavior so that it has window.location.href=".../meme?id= <%= meme.id %>"
Then, on the Express side, you can modify the POST route to GET and get the specific ID in the query string so you can search for it from a database etc. and render the page using res.render()
Just like the example below.
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 }); });
Hope it helps you
updated
As you mentioned the distribution requirements, you can slightly modify the POST routing code above (you can use just the ID or the whole data, depending on the distribution requirements) instead of using res.render()
To render an html page, you simply use res.JSON()
and utilize the JSON response using JS.
Meme.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, } }) });
meme.ejs (you can place any element that will become a meme container for the selected details)
<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>
Then MemeDetails.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 = ''; } }