I'm trying to build an SPA application but it's not rendering the "renderItem" and "renderTotalPrice" functions. I will not add the style file note that when I was just using one js file it was rendering when I separated the files into 4 files it stops render the mentioned two functions I know that I need to create a js file for the navbar instead of coding it in the HTML file but for the next step after I solve this issue.
the code is:
index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" type="text/css" href="styles.css" />
<title>Flying Dutchman</title>
</head>
<body>
<!-- Navigation Bar -->
<nav>
<ul>
<!-- Logo -->
<li id="logo">
<img src="flying_logo.png" alt="" />
</li>
<!-- Navigation Links -->
<li><a href="#" id="drinksLink">Drinks</a></li>
<li><a href="#" id="foodLink">Food</a></li>
<li id="blankSpace"><a href=""></a></li>
<!-- Login Button -->
<li><button id="loginBtn">Login</button></li>
</ul>
</nav>
<!-- Main Content Container -->
<div id="container">
<!-- Drinks and Foods Section -->
<div id="drinksFoods">
<!-- Content for Drinks and Foods will be dynamically populated here -->
</div>
<!-- Payment Section -->
<div id="payment">
<!-- Content for payment will be dynamically populated here -->
</div>
</div>
<!-- JavaScript Controller -->
<script src="./controller.js"></script>
</body>
</html>
controller.js:
import model from "./model.js";
import itemView from "./itemView.js";
import paymentPanel from "./paymentPanel.js";
// Controller
const controller = {
/**
* Controller module responsible for managing user interactions and updating the model and view.
*
* @type {Object}
*/
/**
* Handles data transfer during dragstart and sets the dragged item.
*
* @param {Event} event - The dragstart event.
* @param {Object} item - The item being dragged.
*/
dragStart: function (event, item) {
event.dataTransfer.setData("text/plain", JSON.stringify(item));
},
/**
* Prevents the default behavior to enable drop in the dragenter event.
*
* @param {Event} event - The dragenter event.
*/
dragEnter: function (event) {
event.preventDefault();
},
/**
* Prevents the default behavior to enable drop in the dragover event.
*
* @param {Event} event - The dragover event.
*/
dragOver: function (event) {
event.preventDefault();
},
/**
* Handles the drop operation, adding the dropped item to the order summary.
*
* @param {Event} event - The drop event.
*/
drop: function (event) {
event.preventDefault();
const data = event.dataTransfer.getData("text/plain");
const droppedItem = JSON.parse(data);
model.selectedItems.push(droppedItem);
model.total += droppedItem.price;
paymentPanel.renderTotalPrice();
},
/**
* Initializes the application, sets up event listeners, and renders initial content.
*/
init: function () {
itemView.renderItems(model.drinkItems, "drinksFoods");
paymentPanel.renderTotalPrice();
document
.getElementById("drinksLink")
.addEventListener("click", function () {
itemView.renderItems(model.drinkItems, "drinksFoods");
});
document.getElementById("foodLink").addEventListener("click", function () {
paymentPanel.renderItems(model.foodItems, "drinksFoods");
});
document
.getElementById("checkoutBtn")
.addEventListener("click", function () {
alert("Processing payment. Total amount: $" + model.total.toFixed(2));
});
const orderSummary = document.getElementById("orderSummary");
orderSummary.addEventListener("dragenter", controller.dragEnter);
orderSummary.addEventListener("dragover", controller.dragOver);
orderSummary.addEventListener("drop", controller.drop);
},
/**
* Adds an item to the cart, updates the model, and triggers a view update.
*
* @param {Object} item - The selected item to be added to the cart.
*/
addToCart: function (item) {
model.selectedItems.push(item);
model.total += item.price;
paymentPanel.renderTotalPrice();
},
};
export default controller;
// Initialize the application
controller.init();
model.js
const model = {
/**
* Initializes the model with data for drink and food items, selected items, and the total cost.
*/
drinkItems: [
{
id: 1,
name: "Drink 1",
price: 5.99,
details: "Refreshing beverage",
},
{
id: 2,
name: "Drink 2",
price: 3.99,
details: "Crisp and cool",
},
{
id: 3,
name: "Drink 3",
price: 4.99,
details: "Satisfying drink",
},
{
id: 4,
name: "Drink 4",
price: 6.99,
details: "Delicious drink",
},
{
id: 5,
name: "Drink 5",
price: 7.99,
details: "Tasty drink",
},
{
id: 6,
name: "Drink 6",
price: 8.99,
details: "Refreshing beverage",
},
{
id: 7,
name: "Drink 7",
price: 9.99,
details: "Crisp and cool",
},
{
id: 8,
name: "Drink 8",
price: 10.99,
details: "Satisfying drink",
},
{
id: 9,
name: "Drink 9",
price: 11.99,
details: "Delicious drink",
},
{
id: 10,
name: "Drink 10",
price: 12.99,
details: "Tasty drink",
},
{
id: 11,
name: "Drink 11",
price: 13.99,
details: "Refreshing beverage",
},
{
id: 12,
name: "Drink 12",
price: 14.99,
details: "Crisp and cool",
},
{
id: 13,
name: "Drink 13",
price: 15.99,
details: "Satisfying drink",
},
{
id: 14,
name: "Drink 14",
price: 16.99,
details: "Delicious drink",
},
{
id: 15,
name: "Drink 15",
price: 17.99,
details: "Tasty drink",
},
// Add more items as needed
],
foodItems: [
{ name: "Food 1", price: 7.99, details: "Delicious meal" },
{ name: "Food 2", price: 9.99, details: "Satisfying dish" },
{ name: "Food 3", price: 8.99, details: "Tasty food" },
{ name: "Food 4", price: 10.99, details: "Delicious food" },
{ name: "Food 5", price: 11.99, details: "Satisfying food" },
{ name: "Food 6", price: 12.99, details: "Tasty dish" },
{ name: "Food 7", price: 13.99, details: "Delicious dish" },
{ name: "Food 8", price: 14.99, details: "Satisfying meal" },
{ name: "Food 9", price: 15.99, details: "Tasty meal" },
{ name: "Food 10", price: 16.99, details: "Delicious meal" },
{ name: "Food 11", price: 17.99, details: "Satisfying dish" },
{ name: "Food 12", price: 18.99, details: "Tasty food" },
{ name: "Food 13", price: 19.99, details: "Delicious food" },
{ name: "Food 14", price: 20.99, details: "Satisfying food" },
{ name: "Food 15", price: 21.99, details: "Tasty dish" },
// Add more food items as needed
],
selectedItems: [],
total: 0,
};
export default model;
itemView.js
import { controller } from "./controller.js";
import { model } from "./model.js";
const itemView = {
/**
* Renders a list of items in a specified container.
*
* @param {Object[]} items - The array of items to be rendered.
* @param {string} containerId - The ID of the container element in the HTML.
*/
//itemView
renderItems: function (items, containerId) {
const container = document.getElementById(containerId);
container.innerHTML = "";
items.forEach((item) => {
const itemBox = document.createElement("div");
itemBox.classList.add("itemBox");
itemBox.setAttribute("draggable", true); // Make the item box draggable
const itemName = document.createElement("p");
itemName.textContent = `Name: ${item.name}`;
const itemDetails = document.createElement("p");
itemDetails.textContent = `Price: $${item.price.toFixed(2)}`;
const itemDescription = document.createElement("p");
itemDescription.textContent = `Details: ${item.details}`;
itemBox.appendChild(itemName);
itemBox.appendChild(itemDetails);
itemBox.appendChild(itemDescription);
itemBox.addEventListener("click", function () {
controller.addToCart(item);
});
itemBox.addEventListener("dragstart", function (event) {
controller.dragStart(event, item);
});
container.appendChild(itemBox);
});
},
};
export default itemView;
paymentPanel.js
import { model } from "./model.js";
import { controller } from "./controller.js";
const paymentPanel = {
/**
* Renders the total price in the HTML element with the ID "totalPrice".
*/
// paymentPanel
renderTotalPrice: function () {
const paymentPanel = document.getElementById("payment");
let orderSummary = document.getElementById("orderSummary");
let totalPriceElement = document.getElementById("totalPrice");
let checkoutBtn = document.getElementById("checkoutBtn");
// If orderSummary doesn't exist, create and append it to the paymentPanel
if (!orderSummary) {
orderSummary = document.createElement("div");
orderSummary.textContent = "Order Summary";
orderSummary.id = "orderSummary";
paymentPanel.appendChild(orderSummary);
}
// Clear existing content in orderSummary
orderSummary.innerHTML = "";
// Display selected items with counts in orderSummary
const itemCounts = {}; // Moved the itemCounts object outside the loop
const renderedItems = {}; // Keep track of items that have been rendered
model.selectedItems.forEach((selectedItem) => {
const itemId = selectedItem.id;
// If the item is already in the orderSummary, update the count
if (itemCounts[itemId]) {
itemCounts[itemId]++;
} else {
itemCounts[itemId] = 1;
}
// Check if the item has been rendered before
if (!renderedItems[itemId]) {
// Create a new element for the item with the correct count
const selectedItemElement = document.createElement("p");
selectedItemElement.textContent = `${selectedItem.name} x${
itemCounts[itemId]
} - $${selectedItem.price.toFixed(2)}`;
orderSummary.appendChild(selectedItemElement);
// Mark the item as rendered
renderedItems[itemId] = true;
}
});
// Update the content of totalPriceElement
if (!totalPriceElement) {
totalPriceElement = document.createElement("p");
totalPriceElement.id = "totalPrice";
paymentPanel.appendChild(totalPriceElement);
}
totalPriceElement.textContent = `Total: $${model.total.toFixed(2)}`;
// If checkoutBtn doesn't exist, create and append it to the paymentPanel
if (!checkoutBtn) {
checkoutBtn = document.createElement("button");
checkoutBtn.textContent = "Checkout";
checkoutBtn.id = "checkoutBtn";
paymentPanel.appendChild(checkoutBtn);
}
},
};
export default paymentPanel;
1st you need to import your controller
as a module: Change the script loading from this:
<script src="./controller.js"></script>
to this:
<script type="module">
import { controller } from './controller.js';
// Initialize the application
controller.init();
</script>
And you need some modifications in your JS files:
In the controller.js
:
Change this const controller = {
to this: export const controller = {
. Remove these lines at the end of the file:
export default controller;
// Initialize the application
controller.init();
This export type works with functions/classes but you have an object.
And also change the model.js:
Change this const model = {
to this: export const model = {
. Remove this line at the end of the file:
export default model;
And the result (without styles because you have not shared them us):