skip to Main Content

I am creating a product page that show all available product in the form of card. This image show’s how products is displayed on the products page I want a functionality that whenever user click’s on any product card from the available product cards a request is to be made to server to open productshowcase page with complete product detailImages show’s the file i need to render in responce. I tried some method to do that, but none worked well.

The code for product card is

<div class="product-display-c">
                    <div class="product-card-holding-c">
                        <!--  -->
                        <% for (let i=0; i < data.length; i++) {%>
                            <div id="<%= data[i].id%>" class="product-card-c">
                                <div class="product-image-c">
                                    <img class="product-card-image" src="<%= data[i].images[0]%>"
                                        alt="random image" />
                                </div>
                                <div class="product-detail-c">
                                    <p class="product-name">
                                        <%= data[i].p_name%>
                                    </p>
                                    <p class="product-sp">Rs. <%= data[i].selling_price%>
                                    </p>
                                    <p class="product-mrp">M.R.P: Rs. <span>
                                            <%= data[i].mrp%>
                                        </span> </p>
                                    <p class="product-discount">
                                        <%= data[i].mrp - data[i].selling_price%> off
                                    </p>
                                    <p class="product-quality">Quality verified</p>
                                </div>
                            </div>
                            <% }%>
                    </div>
                </div>

This code create cards as per data received from database.

after that I created a javascript code to send request to server to open productshowcase page with complete product detail. The code is like

document.querySelectorAll('.product-card-c').forEach((div) => {
  div.addEventListener('click', function(event) {
    console.log(event.target.closest('.product-card-c').id);
    const selectedId =event.target.closest('.product-card-c').id;
    fetch(`/products/${selectedId}`)
          .then(response => console.log(response.text()))
  });
});

this code send the id of clicked card to the server. The server side code to handle this is like
app.get('/products/:id', async function(req, res) { try { const selectedId = await db.query(SELECT * FROM products WHERE id=${req.params.id}); res.render("productshowcase.ejs", {product :selectedId.rows}); } catch (err) { console.log(err); } });

I don’t know what is the issue but nothing happen when i click the card.

Although the server response when i try to hit browser url section with url localhost:3000/products/2 the server open productshowcase page without CSS apllied to it and with lots of error in console like
"Failed to load resource: the server responded with a status of 404 (Not Found)
great-value-trademart.png:1
Failed to load resource: the server responded with a status of 404 (Not Found)
header.js:1

   Failed to load resource: the server responded with a status of 404 (Not Found)

1:1 Refused to execute script from ‘http://localhost:3000/products/jscript/header.js’ because its MIME type (‘text/html’) is not executable, and strict MIME type checking is enabled.
catagory-2.jpg:1

   Failed to load resource: the server responded with a status of 404 (Not Found)"

I am totally stucked. Can anyone help me to find where is the error. Thanks in advance.

I tried searching for the correct method to send request to the server but failed to find the right one

3

Answers


  1. Chosen as BEST ANSWER

    import express from "express";
    import ejs from "ejs";
    import bodyParser from "body-parser";
    import pg from "pg";
    import {dirname} from "path";
    import { fileURLToPath } from "url";
    const __dirname = dirname(fileURLToPath(import.meta.url))
    
    const app = express(); // Create an express app
    const port = 3000;
    
    app.set('view engine', 'ejs'); // set ejs as view engine
    // app.use(express.static("public")); // Define folder for static file "app.use is a middleware"
    app.use(bodyParser.urlencoded({ extended: true })); // Help to get data from frontend
    
    app.use(express.static(__dirname + '/public/'));
    const db = new pg.Client({
        user: "postgres",
        host: "localhost",
        database: "greatvalue_db",
        password: "123456",
        port: 5432,
    });
    
    db.connect();
    
    app.get("/", (req, res) => {
        res.render("index.ejs");
    })
    
    app.get("/user", (req, res) => {
        res.render("user.ejs");
    })
    
    app.get("/dealer-enquiry", (req, res) => {
        res.render("dealerEnquiry.ejs");
    })
    
    app.post("/dealer-enquiry", async (req, res) => {
        const entry = req.body;
        // console.log(entry);
        try {
            await db.query("INSERT INTO dealer_enquiry (fname, lname, email, pnumber, address, city,pincode,state,item1,item2,item3,item4,item5,item6,item7,enquiry) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16)",
                [entry.first_name, entry.last_name, entry.email_id, entry.phone_number, entry.address, entry.city, entry.pin_code, entry.state, entry.item1, entry.item2, entry.item3, entry.item4, entry.item5, entry.item6, entry.item7, entry.enquiry]);
                // res.sendStatus(200);
                res.redirect("/dealer-enquiry");
        } catch (err) {
            console.log(err);
        }
    });
    
    app.get("/about", (req, res) => {
        res.render("about.ejs");
    })
    
    app.get("/career", (req, res) => {
        res.render("career.ejs");
    })
    
    app.get("/contact", (req, res) => {
        res.render("contact.ejs");
    })
    
    app.get("/products", async (req, res) => {
        try {
            const cardValue = await db.query("SELECT id, images, p_name, selling_price, mrp FROM products");
                // res.sendStatus(200);
                // console.log(cardValue.rows);
                res.render("products.ejs", {data :cardValue.rows});
        } catch (err) {
            console.log(err);
        }
        
    })
    
    app.get('/products/:id', async function(req, res) {
        try {
            const selectedId = await db.query(`SELECT * FROM products WHERE id=${req.params.id}`);
                res.render("productshowcase.ejs", {product :selectedId.rows});
        } catch (err) {
            console.log(err);
        }
    });
    
    app.listen(port, () => {
        console.log(`Server started on port ${port}`);
    })


  2. EJS is a server-side template engine, which means the HTML is created on the server and typically sent back as a HTTP response. What you are trying to do is make a fetch request which will get that rendered HTML and store it as text when you do .then(response => console.log(response.text())). After that nothing happens. The HTML won’t magically append itself to the DOM or replace the existing HTML on your page.

    When using fetch it’s to typically get data from the sever usually as JSON and from that JSON payload you can loop through is properties and append/replace HTML elements to the DOM. You would need to write code to do that. Alternatively you could just send a url back as the response and redirect the browser to navigate to the new url.

    My honest advice if sticking with EJS would be

    Option 1:

    Warp each card in an <a> tag with the id of each product appended to the href attribute. That way when your user clicks on a card the browser sends a standard GET request to /products/:id and is redirected appropriately.

    This means you can delete all of that document.querySelectorAll('.product-card-c').forEach code.

    An example would be:

    <div class="product-display-c">
       <div class="product-card-holding-c">
          <!--  -->
          <% for (let i=0; i < data.length; i++) {%>
           <a href="/products/<%= data[i].id%>">  <!-- add this a tag  -->
             <div id="<%= data[i].id%>" class="product-card-c">
                <div class="product-image-c">
                   <img class="product-card-image" src="<%= data[i].images[0]%>" alt="random image" />
                </div>
                <div class="product-detail-c">
                   <!-- rest of your code -->
                </div>
             </div>
            </a>
          <% }%>
       </div>
    </div>
    

    Option 2:

    Don’t change any HTML code and instead of sending a fetch request use your click handler to navigate to the new url like so:

    document.querySelectorAll('.product-card-c').forEach((div) => {
      div.addEventListener('click', function(event) {
        console.log(event.target.closest('.product-card-c').id);
        const selectedId =event.target.closest('.product-card-c').id;
        window.location.assign(`http://localhost:3000/products/${selectedId}`); //< add this
      });
    });
    
    Login or Signup to reply.
  3. <%- include("partials/header.ejs"); %>
    <section class="product-detail-display-s">
        <div class="pd-aliner-c">
            <div class="pd-highlight-c">
                <div class="pd-image-showcase-c">
                    <div class="pd-image-main-c">
                        <img class="pd-main-img" src="<%= product[0].images[0]%>" alt="" />
                    </div>
                    <div class="pd-image-sub-c">
                        <div class="pd-sub-img-c">
                            <img class="pd-sub-img" src="<%= product[0].images[0]%>" alt="" />
                            <img class="pd-sub-img" src="<%= product[0].images[1]%>" alt="" />
                            <img class="pd-sub-img" src="<%= product[0].images[2]%>" alt="" />
                            <img class="pd-sub-img" src="<%= product[0].images[3]%>" alt="" />
                        </div>
                    </div>
                </div>
                <div class="pd-abstract-c">
                    <div class="product-name-c">
                        <p class="pd-product-name"><%= product[0].p_name%></p>
                    </div>
                    <div class="product-status-c">
                        <p class="product-stock-status"><%= product[0].in_stock >0 ? "In Stock" : "Out of stock" %></p>
                        <p class="product-rating-status">Rating <span><%= product[0].rating%></span> <i class="fa-solid fa-star" aria-hidden="true"></i></p>
                    </div>
                    <div class="product-mini-abstract-c">
                        <div class="product-price-c">
                            <p class="selling-price">Rs. <span><%= product[0].selling_price%></span> </p>
                            <p class="taxMsg">(Inclusive of all taxes)</p>
                            <p class="mrp">MRP. <span><%= product[0].mrp%></span> </p>
                            <p class="discount-value">Rs. <span><%= product[0].mrp-product[0].selling_price%></span> Off</p>
                        </div>
                        <div class="product-feature-c">
                            <p class="product-feature-heading">Features</p>
                            <ul class="product-feature-list">
                                <% for (let i=0; i < product[0].feature.length; i++) {%>
                                <li class="product-feature-listitem"><%= product[0].feature[i]%></li>
                                <% }%>
                            </ul>
                        </div>
                        <div class="buy-cart-btn-c">
                            <button class="Add-to-cart">Add to cart</button>
                            <button class="buy-btn">Buy now</button>
                        </div>
                        <div class="company-feature-tray-c">
                            <div class="company-feature-point-c">
                                <i class="fa-solid fa-award" aria-hidden="true"></i>
                                <p class="company-feature-point">Great Value Assured</p>
                            </div>
                            <div class="company-feature-point-c">
                                <i class="fa-solid fa-arrow-right-arrow-left" aria-hidden="true"></i>
                                <p class="company-feature-point">7 days exchange</p>
                            </div>
                            <div class="company-feature-point-c">
                                <i class="fa-solid fa-truck" aria-hidden="true"></i>
                                <p class="company-feature-point">Doorstep delivery</p>
                            </div>
                            <div class="company-feature-point-c">
                                <i class="fa-solid fa-thumbs-up" aria-hidden="true"></i>
                                <p class="company-feature-point">100% genuine product</p>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
            <div class="pd-full-c">
                <div class="pd-details-c">
                    <div class="pd-details-heading-c">
                        <p class="pd-details-heading">Details</p>
                    </div>
                    <div class="pd-details-table-c">
                        <table>
                            <tbody>
                                <tr class="pd-tr">
                                    <td class="pd-td-name">Name</td>
                                    <td class="pd-td-value">fbfck bciuchic sdiusci csdhsc oc jsiosc</td>
                                </tr>
                                <tr class="pd-tr">
                                    <td class="pd-td-name">Colour</td>
                                    <td class="pd-td-value"></td>
                                </tr>
                                <tr class="pd-tr">
                                    <td class="pd-td-name">Material</td>
                                    <td class="pd-td-value"></td>
                                </tr>
                                <tr class="pd-tr">
                                    <td class="pd-td-name">Dimensions</td>
                                    <td class="pd-td-value"></td>
                                </tr>
                                <tr class="pd-tr">
                                    <td class="pd-td-name">Weight Limit</td>
                                    <td class="pd-td-value"></td>
                                </tr>
                                <tr class="pd-tr">
                                    <td class="pd-td-name">Sutable for</td>
                                    <td class="pd-td-value"></td>
                                </tr>
                                <tr class="pd-tr">
                                    <td class="pd-td-name">Number of wheels</td>
                                    <td class="pd-td-value"></td>
                                </tr>
                                <tr class="pd-tr">
                                    <td class="pd-td-name">Net Quantity</td>
                                    <td class="pd-td-value"></td>
                                </tr>
                                <tr class="pd-tr">
                                    <td class="pd-td-name">Item weight</td>
                                    <td class="pd-td-value"></td>
                                </tr>
                                <tr class="pd-tr">
                                    <td class="pd-td-name">Installation type</td>
                                    <td class="pd-td-value"></td>
                                </tr>
                                <tr class="pd-tr">
                                    <td class="pd-td-name">Assembly required</td>
                                    <td class="pd-td-value"></td>
                                </tr>
                                <tr class="pd-tr">
                                    <td class="pd-td-name">Brand</td>
                                    <td class="pd-td-value"></td>
                                </tr>
                                <tr class="pd-tr">
                                    <td class="pd-td-name">Model number</td>
                                    <td class="pd-td-value"></td>
                                </tr>
                                <tr class="pd-tr">
                                    <td class="pd-td-name">Item code</td>
                                    <td class="pd-td-value"></td>
                                </tr>
                                <tr class="pd-tr">
                                    <td class="pd-td-name">Warranty</td>
                                    <td class="pd-td-value"></td>
                                </tr>
                                <tr class="pd-tr">
                                    <td class="pd-td-name">In the box</td>
                                    <td class="pd-td-value"></td>
                                </tr>
                            </tbody>
                        </table>
                    </div>
                </div>
                <div class="pd-description-c">
                    <div class="pd-description-heading-c">
                        <p class="pd-description-heading">Description</p>
                    </div>
                    <div class="pd-description-list-c">
                        <ul class="pd-description-list">
                            <li class="pd-description-listitem">ERGONOMIC DESIGN: The backrest of this desk chair fit the natural curve of the human body, So that you can maintain a healthy and comfortable sitting posture. Thickened cushions provide better sitting experience with high density breathable mesh.</li>
                            <li class="pd-description-listitem">COMFORTABLE SEAT - Thick moulded pu seat with Mesh fabric and Large seat for a sweat-free sitting experience. The adjustable headrest is designed to support keeping your whole body cool and comfortable position to your neck and head.</li>
                            <li class="pd-description-listitem">HIGH BACK SUPPORT- The ergonomic design with back support provides maximum ease for long sitting sessions.</li>
                            <li class="pd-description-listitem">ADJUSTABLE HEIGHT & TILT MODE : The rocking mode allows increased relaxation, pull the lever outwards to recline and push it inwards to stop with class 4 gaslift. A tilt-tension knob underneath the chair seat makes it easier to rock back in your chair.</li>
                            <li class="pd-description-listitem">ADJUSTABLE LUMBAR SUPPORT : Adjust lumbar support according to your comfort.</li>
                        </ul>
                    </div>
                </div>
            </div>
        </div>
    </section>
    <%- include("partials/footer.ejs"); %>

    This what i get as result

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search