Dashboard Products & Conditionals

shopping bag logo

Refactor

Just before we add to our code, it will be a good time to refactor. A refactor will make our code more readable and maintainable.

The renderProducts() function currently generates products for the home page, and it will soon generate products for the dashboard view. This will be additional code so our function could begin to get larger and messy. To help, the code can be extracted into separate functions:

// add two functions to generate products for home and dashboard pages:
function renderProductCards(container, products) {}
function renderTableRows(container, products) {}

renderProducts();

These functions will be passed the container (parent element on the page to add products to), and the products to create. Then we can move the product generating code to the new function:

  • Cut the full loop section from the renderProducts() function (everything except const productList =).
  • Paste this into renderProductCards().
  • Replace productList.appendChild(card); with container.appendChild(card); to use the container passed to the function.
function renderProducts() {
    const productList = document.getElementById("product-list");
}

function renderProductCards(container, products) {
    products.forEach(function (product) {
        const card = document.createElement("article");
        card.setAttribute("class", "product-card");
        card.innerHTML = `<section class="product-image">
      <img
        src="images/t-shirt-blue.png"
        alt="blue t-shirt with short sleeves"
        class="product-image"
      />
    </section>
    <section class="product-details">
        <h3>${product.name}</h3>
        <p>${product.description}</p>
        <p class="price">$${product.price}</p>
    </section>`;

        // productList.appendChild(card);
        container.appendChild(card);
    });
}

The final stage is to invoke the renderProductCards function and pass the required arguments:

function renderProducts() {
    const productList = document.getElementById("product-list");
    renderProductCards(productList, products);
}

This will run the code in the renderProductCards function, using the same productList container and products. Keeping our functions smaller and more focused on a particular task.

Creating dashboard products

We will also use this product data to generate the products in the dashboard page, inside the <table>. Locate the <tbody> and clear out the contents:

<!-- dashboard.html -->
<table>
  <thead>
    <tr>
      <th>Title</th>
      <th>Price</th>
      <th>Actions</th>
    </tr>
  </thead>
  <tbody id="product-table"></tbody>
</table>

Also, add the id="product-table" as this will be the container to add products to. The renderTableRows function will generate these products. Complete the function as follows:

// script.js
function renderTableRows(container, products) {
    products.forEach(function (product) {
        const row = document.createElement("tr");
        row.innerHTML = `
            <td>${product.name}</td>
            <td>$${product.price}</td>
            <td>
                <button class="edit-btn">Edit</button>
                <button class="delete-btn">Delete</button>
            </td>
        `;
        container.appendChild(row);
    });
}

This works in a similar way to the home page. We pass the function the container to add the products to, and the product data. This will loop over the available products and generate HTML rows.

Update the renderProducts() function to call renderTableRows(), along with adding the container to attach to:

function renderProducts() {
    const productList = document.getElementById("product-list");
  // select the table from the dashboard page
    const productTable = document.getElementById("product-table");
    renderProductCards(productList, products);
  // call function to generate products
    renderTableRows(productTable, products);
}

This will generate products for both pages, although we only need one page at a time. We can reduce the workload by only running the function for the page we are currently viewing using a conditional.

What is a conditional?

A conditional is a way to decide which path to take, a decision between two or more options. Examples include:

  • Show the user account area if logged in, if not, redirect to the home page.
  • To switch between a sun/moon icon when using light or dark mode.
  • To end a game if the players score is 0.

This is often decided by if something is true or false, referred to as a Boolean value. We want to detect the current page to know which products to render. Here is a simple example if a popular conditional, the if/else statement:

let loggedIn = true;

if (loggedIn) {
    console.log("You are logged in!");
} else {
    console.log("Please log in!");
}

This example will log "You are logged in!" as the value of the if statement is true. If loggedIn is set to false, the else block will run.

The window

We need a way to detect the page we are viewing. In your browsers console, type window and press enter. The window object represents the browsers window, explore the contents and you will see information relating to the web document. You will also see the functions we created as these are global. The property we are interesed in is location, expand this and you will a property called pathname. This pathname will be a path to the current file:

"/Your_Folder_Location/online-store/index.html"

Checking the current page

This is a string of text, and JavaScript has a string method available called includes(). This will return true or false depending on the value we are checking. We need to check if the string includes the file name of dashboard.html. Update the renderProducts() function to include the if/else statement:

function renderProducts() {
  const productList = document.getElementById("product-list");
  const productTable = document.getElementById("product-table");
  // add if/else statement
  if (window.location.pathname.includes("dashboard.html")) {}
  else {}
  renderTableRows(productTable, products);
  renderProductCards(productList, products);
}

Then move the renderTableRows() and renderProductCards() functions inside:

function renderProducts() {
  const productList = document.getElementById("product-list");
  const productTable = document.getElementById("product-table");
  if (window.location.pathname.includes("dashboard.html")) {
    renderTableRows(productTable, products);
  } else {
    renderProductCards(productList, products);
  }
}

This ensures the correct products function is ran for the current page.

Switch between the home and the dashboard pages to see the different product views. Both use the same product data, but rendered using different elements.

Final project code

// script.js
let products = [
    {
        name: "Stylish long-sleeve t-shirt in blue / medium",
        description: "A stylish long sleeve blue t-shirt, in size medium.",
        price: 20.95,
    },
    {
        name: "Stylish long-sleeve t-shirt in red / large",
        description: "A stylish long sleeve red t-shirt, in size large.",
        price: 21.95,
    },
];

function renderProducts() {
    const productList = document.getElementById("product-list");
    const productTable = document.getElementById("product-table");
    if (window.location.pathname.includes("dashboard.html")) {
        renderTableRows(productTable, products);
    } else {
        renderProductCards(productList, products);
    }
}

function renderProductCards(container, products) {
    products.forEach(function (product) {
        const card = document.createElement("article");
        card.setAttribute("class", "product-card");
        card.innerHTML = `<section class="product-image">
      <img
        src="images/t-shirt-blue.png"
        alt="blue t-shirt with short sleeves"
        class="product-image"
      />
    </section>
    <section class="product-details">
        <h3>${product.name}</h3>
        <p>${product.description}</p>
        <p class="price">$${product.price}</p>
    </section>`;

        container.appendChild(card);
    });
}

function renderTableRows(container, products) {
    products.forEach(function (product) {
        const row = document.createElement("tr");
        row.innerHTML = `
            <td>${product.name}</td>
            <td>$${product.price}</td>
            <td>
                <button class="edit-btn">Edit</button>
                <button class="delete-btn">Delete</button>
            </td>
        `;
        container.appendChild(row);
    });
}

renderProducts();