Script wont display the total prices - javascript

Im new to coding. Can anyone see why my script wont display the total prices of the different providers when I click calculate button? (I have two json files for data consumption.json and providers.json) I only want someone to look over and look for any mistakes I can have made.
index.html
<!DOCTYPE html>
<html>
<head>
<title>Energy Consumption Calculator</title>
</head>
<body>
<h1>Energy Consumption Calculator</h1>
<form id="calculation-form">
<div>
<label for="fixedPrice">Fixed Price:</label>
<input type="number" id="fixedPrice" name="fixedPrice">
</div>
<div>
<label for="variablePrice">Variable Price:</label>
<input type="number" id="variablePrice" name="variablePrice">
</div>
<div>
<label for="spotPrice">Spot Price:</label>
<input type="number" id="spotPrice" name="spotPrice">
</div>
<button type="submit" onclick="calculatePrice()">Calculate</button>
</form>
<div id="output"></div>
</main>
</body>
</html>
app.js
async function getData(url) {
const response = await fetch(url);
console.log(response);
return response.json();
}
async function calculatePrice() {
const consumptionData = await getData("consumption.json");
const providersData = await getData("providers.json");
let prices = [];
let fixedtotalPrice = 0;
let variabletotalPrice = 0;
let hourlytotalPrice = 0;
let monthlytotalPrice = 0;
for (const provider of providersData) {
for (const consumption of consumptionData) {
if (provider.pricingModel === "fixed") {
// Get the fixedPrice value from user input
const fixedPrice = parseFloat(document.getElementById("fixedPrice").value);
fixedtotalPrice += fixedPrice * consumption.consumption;
} else if (provider.pricingModel === "variable") {
// Get the variablePrice value from user input
const variablePrice = parseFloat(document.getElementById("variablePrice").value);
variabletotalPrice += consumption.consumption * variablePrice;
} else if (provider.pricingModel === "spotPrice") {
// Get the spotPrice value from user input
const spotPrice = parseFloat(document.getElementById("spotPrice").value);
hourlytotalPrice += consumption.consumption * spotPrice;
} else if (provider.pricingModel === "spotPrice") {
// Get the spotPrice value from user input
const spotPrice = parseFloat(document.getElementById("spotPrice").value);
monthlytotalPrice += spotPrice * consumption.consumption;
}
}
}
prices.push({ provider: "Vest Energi", totalPrice: fixedtotalPrice });
prices.push({ provider: "Øst Energi", totalPrice: variabletotalPrice });
prices.push({ provider: "Nord Energi", totalPrice: hourlytotalPrice });
prices.push({ provider: "Syd Energi", totalPrice: monthlytotalPrice });
let output = "<ul>";
for (const price of prices) {
output += `<li>${price.provider}: ${price.totalPrice}</li>`;
}
output += "</ul>";
document.getElementById("output").innerHTML = output;
}
const form = document.getElementById("calculation-form");
form.addEventListener("submit", function (event) {
event.preventDefault();
calculatePrice();
});
Can't find the mistake.Dont think it has anything to with the json files, but something in my code.

Related

UI not updating document.getElementById("").textContent

Posting this again because I did not have enough code posted before and the title was wrong. I created an object from a form that returns a grossIncome. In Js I have a function that will calculate the ei based on the gross income using 2 if statements and then updates it in the UI. When I console.log (), it appears to see the value and correctly, however the UI does not update.
index.html
<form name="formFill" id="form">
<input name="income" type="number" inputmode="numeric" id="incomeTextBox" placeholder="Gross Income" required>
<select name="workingProvince" id="provinces">
<option value="Ontario">Ontario</option>
<option value="Quebec">Quebec</option>
...
</select>
<button type="submit" id="calculate">Calculate</button>
</form>
<div class="ei">
<h3>EI Deduction</h3>
<p id="eiValue">- $0</p>
</div>
<script type="module">
import { submitForm } from './javascript/taxCalculatorIndex.js'
document.getElementById('form').addEventListener('submit', submitForm)
</script>
calculations.js
export const calculateEITax = (grossIncome) => {
console.log ('calculateEITaxGross:', grossIncome)
let ei;
if (grossIncome <= 60300) {
console.log ('grossIncome <= 60300:', grossIncome <= 60300)
// console.log ('ei:', grossIncome * 0.0158 )
ei = grossIncome * 0.0158;
}
else {
ei = 60300 * 0.158;
}
return ei;
}
index.js
import {calculateEITax} from './calculations.js'
export const submitForm = (event) => {
event.preventDefault()
const form = document.getElementById('form');
const data = new FormData(form);
const dataObject = {};
for (const [key, value] of data.entries()) {
dataObject[key] = value;
};
let grossIncome = dataObject.income;
let province = dataObject.workingProvince;
calculateTax(grossIncome, province);
}
const calculateTax = (grossIncome, province) => {
const eiTax = calculateEITax(grossIncome);
console.log("eiTax: ", eiTax)
updateDOM(eiTax);
}
const updateDOM = (eiTax) => {
document.getElementById("eiValue").textContent = `- $${eiTax}`;
console.log ("eiValue:", document.getElementById("eiValue").textContent = `- $${eiTax}` )
}
console.log output:
calculateEITaxGross: 30000
calculations.js:423 grossIncome <= 60300: true
index.js:95 eiTax: 474.00000000000006
index.js:127 eiValue: - $474.00000000000006
But my UI updates undefined
Anyone know why this is?

How do I make a button delete an item from array in JavaScript?

I'm currently making a Library project, and I made it so that each book entered is stored in an array (in this case, the array is myLibrary). Then I made it so that each book in the array creates a new div with the class of "card." I've implemented a "Remove Button" for each card, but I'm not sure as to how I can make the button delete the book from the array. Any help would be appreciated, thank you.
I've tried
const remBtn = document.createElement("button");
card.appendChild(remBtn);
remBtn.textContent = "Remove";
remBtn.onclick = remBook;
// Remove book function
function remBook() {
const findBook = myLibrary.findIndex((element) => element === book);
const delBook = myLibrary.slice(findBook, 1);
}
Here are my codes:
html:
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Library</title>
<link rel="stylesheet" href="./style.css" />
</head>
<body>
<div class="header">Library</div>
<form id="submitInput" action="">
<label for="title">Title:</label>
<input type="text" id="formTitle" name="title" required />
<label for="author">Author:</label>
<input type="text" id="formAuthor" name="author" required />
<label for="page">Page:</label>
<input type="text" id="formPage" name="page" required />
<div class="read">
<label for="read">Read</label>
<input type="checkbox" id="formRead" name="read" value="" />
</div>
<input type="submit" id="submitBtn" value="Add Book" />
</form>
<div class="currentDisplay"></div>
</body>
<script src="./script.js"></script>
</html>
JS:
// Data inputs
let myLibrary = [
{
title: "test",
author: "test",
page: "123",
read: true,
},
];
// Object constructor
function book(title, author, page, read) {
this.title = title;
this.author = author;
this.page = page;
this.read = read;
}
// Add new books to library
function addBookToLibrary() {
let a = document.getElementById("formTitle").value;
let b = document.getElementById("formAuthor").value;
let c = document.getElementById("formPage").value;
let d = document.getElementById("formRead").checked;
if (a !== "" && b !== "" && c !== "") {
myLibrary.push(new book(a, b, c, d));
}
}
const submit = document.getElementById("submitInput");
submit.addEventListener("submit", () => {
event.preventDefault();
addBookToLibrary();
submit.reset();
displayBooks();
});
// Display each book as cards
function displayBooks() {
const currentDisplay = document.querySelector(".currentDisplay");
currentDisplay.textContent = "";
myLibrary.forEach((myLibrary) => {
let card = document.createElement("div");
card.classList.add("card");
currentDisplay.appendChild(card);
for (let key in myLibrary) {
const text = document.createElement("p");
text.textContent = `${key}: ${myLibrary[key]}`;
card.appendChild(text);
}
const readBtn = document.createElement("button");
card.appendChild(readBtn);
if (myLibrary.read === true) {
readBtn.textContent = "Read";
}
if (myLibrary.read === false) {
readBtn.textContent = "Not Read";
}
readBtn.addEventListener("click", () => {
if (readBtn.textContent === "Read") {
readBtn.textContent = "Not Read";
myLibrary.read = false;
} else if (readBtn.textContent === "Not Read") {
readBtn.textContent = "Read";
myLibrary.read = true;
}
});
const remBtn = document.createElement("button");
card.appendChild(remBtn);
remBtn.textContent = "Remove";
remBtn.onclick = remBook;
});
}
// Remove book function
function remBook() {
const findBook = myLibrary.findIndex((element) => element === book);
const delBook = myLibrary.slice(findBook, 1);
}
displayBooks();
First let's give each Book object a unique property.
// Object constructor
function Book(title, author, page, read) {
this.bookId = `book${++Book.id}`;
this.title = title;
this.author = author;
this.page = page;
this.read = read;
}
//static property
Book.id = 0;
While rendering a book we use the bookId property as class name for the div. This will be used for deleting the element.
card.classList.add(`${myLibrary.bookId}`);
Inside remove book function, we find the book using bookId property. we use the splice method to remove an element from array. Then we call the remove method on div element to delete the div.
// Remove book function
function remBook() {
const bookId = this.parentElement.classList[1];
const findBook = myLibrary.findIndex(
(element) => element.bookId === bookId
);
const delBook = myLibrary.splice(findBook, 1);
this.parentElement.remove();
}
// Data inputs
let myLibrary = [{
title: 'test',
author: 'test',
page: '123',
read: true,
}, ];
// Object constructor
function Book(title, author, page, read) {
this.bookId = `book${++Book.id}`;
this.title = title;
this.author = author;
this.page = page;
this.read = read;
}
//static property
Book.id = 0;
// Add new books to library
function addBookToLibrary() {
let a = document.getElementById('formTitle').value;
let b = document.getElementById('formAuthor').value;
let c = document.getElementById('formPage').value;
let d = document.getElementById('formRead').checked;
if (a !== '' && b !== '' && c !== '') {
myLibrary.push(new Book(a, b, c, d));
}
}
const submit = document.getElementById('submitInput');
submit.addEventListener('submit', () => {
event.preventDefault();
addBookToLibrary();
submit.reset();
displayBooks();
});
// Display each book as cards
function displayBooks() {
const currentDisplay = document.querySelector('.currentDisplay');
currentDisplay.textContent = '';
myLibrary.forEach((myLibrary) => {
let card = document.createElement('div');
card.classList.add('card');
card.classList.add(`${myLibrary.bookId}`);
currentDisplay.appendChild(card);
for (let key in myLibrary) {
const text = document.createElement('p');
text.textContent = `${key}: ${myLibrary[key]}`;
card.appendChild(text);
}
const readBtn = document.createElement('button');
card.appendChild(readBtn);
if (myLibrary.read === true) {
readBtn.textContent = 'Read';
}
if (myLibrary.read === false) {
readBtn.textContent = 'Not Read';
}
readBtn.addEventListener('click', () => {
if (readBtn.textContent === 'Read') {
readBtn.textContent = 'Not Read';
myLibrary.read = false;
} else if (readBtn.textContent === 'Not Read') {
readBtn.textContent = 'Read';
myLibrary.read = true;
}
});
const remBtn = document.createElement('button');
card.appendChild(remBtn);
remBtn.textContent = 'Remove';
remBtn.onclick = remBook;
});
}
// Remove book function
function remBook() {
const bookId = this.parentElement.classList[1];
const findBook = myLibrary.findIndex(
(element) => element.bookId === bookId
);
const delBook = myLibrary.splice(findBook, 1);
this.parentElement.remove();
}
displayBooks();
<div class="header">Library</div>
<form id="submitInput" action="">
<label for="title">Title:</label>
<input type="text" id="formTitle" name="title" required />
<label for="author">Author:</label>
<input type="text" id="formAuthor" name="author" required />
<label for="page">Page:</label>
<input type="text" id="formPage" name="page" required />
<div class="read">
<label for="read">Read</label>
<input type="checkbox" id="formRead" name="read" value="" />
</div>
<input type="submit" id="submitBtn" value="Add Book" />
</form>
<div class="currentDisplay"></div>
I think you can add specific ids whenever you add a new card. And call the card classes using querySelectorAll. That will return you a nodelist. Loop that nodelist and check if the specific id that you are click right now match with the looped element's id. If true, you can do your stuffs in that loop cuz whatever you're doing will only apply to the button that you're clicking.
I made a sample here. By the way, I used JSON to check the condition in string state.
function remBook(obj) {
let card = document.querySelectorAll(".card");
for(let x=0; x<card.length; x++) {
if(JSON.stringfy(card[y].id) === JSON.stringfy(obj.id) {
/* You can do your stuff here using index */
}
}
}
https://jsfiddle.net/xw26rbvc/

An event listener is only created for the last element in forEach loop

I have a firebase database and I want to get all the chats and add an HTML element to all of them. Each div has a password input and a button. I made a forEach() loop but it only makes an event listener for the last one. I'm not very experienced so it is probably a simple problem. This is my code:
get(ref(db, "chats")).then((snapshot)=>{
snapshot.forEach((child)=>{
var html = "";
var childName = child.val().chatname;
var childPassword = child.val().chatpassword;
console.log(childName);
html += `
<li>
<div class="chat-login-container">
<h3>`+childName+`</h3>
<input id="`+childName+`-input" type="password" placeholder="Enter Chat Password">
<button id="`+childName+`-button" class="login">Enter</button>
</div>
</li>
`;
messages.innerHTML += html;
var button = document.getElementById(childName+"-button");
var passwordInput = document.getElementById(childName+"-input");
button.addEventListener("click", ()=>{
get(ref(db, "chats/"+childName)).then((snapshot) =>{
if(passwordInput==childPassword){
chat = childName;
console.log("Logging in to "+childName);
messages.innerHTML = "";
start();
}else{
window.alert("Incorrect password, please try again");
}
}).catch((error)=>{
console.log(error);
});
});
});
}).catch((error)=>{
console.log(error);
});
Because, you are capturing the button by ID. It will capture the last ID recorded.
Instead use querySelector.
Try below, which is not a proper code, you need to tweak based on error messages.
get(ref(db, "chats")).then((snapshot) => {
snapshot.forEach((child) => {
var html = "";
var childName = child.val().chatname;
var childPassword = child.val().chatpassword;
console.log(childName);
html += `
<li>
<div class="chat-login-container">
<h3>`+ childName + `</h3>
<input type="hidden" class="childname" value="`+ childname + `">
<input type="hidden" class="childPassword" value="`+ childPassword + `">
<input id="`+ childName + `-input" class="password" type="password" placeholder="Enter Chat Password">
<button id="`+ childName + `-button" class="login">Enter</button>
</div>
</li>
`;
messages.innerHTML += html;
});
const chatLoginContainers = document.querySelectorAll('.chat-login-container');
chatLoginContainers.forEach((element) => {
const loginBtn = element.querySelector('.login');
loginBtn.addEventListener('click', (event) => {
const childNameEle = event.target.closest('li').querySelector('.childname');
const childPasswordEle = event.target.closest('li').querySelector('.childPassword');
const passwordEle = event.target.closest('li').querySelector('.password');
const childNameVal = childNameEle.value;
const childPasswordVal = childPasswordEle.value;
const passwordVal = passwordEle.value;
get(ref(db, "chats/" + childNameVal)).then((snapshot) => {
if (passwordVal == childPasswordVal) {
chat = childNameVal;
console.log("Logging in to " + childNameVal);
messages.innerHTML = "";
start();
} else {
window.alert("Incorrect password, please try again");
}
}).catch((error) => {
console.log(error);
});
})
});
}).catch((error) => {
console.log(error);
});

Getting an Uncaught TypeError: Cannot set property 'onclick' of null with <script> at the end

I've looked at previous questions like this and cannot find the answer to my problem. I am working in javascript creating a checkout screen and I have two onclicks for two different html files but when I go to the html file for both it says that the other onclick is null. I have tried window.load and moving the script to the bottom of the
var cart = [];
var search = document.getElementById("addItem");
let placement = 0;
var cartElement = document.getElementById("showCart");
var cartTotal = document.getElementById("totalCart");
search.onclick = function(e) {
var userInput = document.getElementById("query").value;
var cartHTML = "";
e.preventDefault();
placement = 0;
for (i = 0; i < menu.length; i++) {
if (menu[i][0].includes(userInput)) {
cart.push(menu[i]);
placement++;
}
}
if (placement == 0) {
alert("Menu option not included. Please try again.");
}
cart.forEach((item, Order) => {
var cartItem = document.createElement("span");
cartItem.textContent = item[0] + " (" + item[1] + ")";
cartHTML += cartItem.outerHTML;
});
cartElement.innerHTML = cartHTML;
}
window.onload = function() {
var checkout = document.getElementById("addCartButton");
checkout.onclick = function(event) {
cart.forEach()
var cartTotalHTML = "";
event.preventDefault();
cart.forEach(Item, Order => {
var totalInCart = 0;
var writeCart = document.createElement("span");
totalInCart += Order[1];
});
writeCart.textContent = cartTotal += item[1];
cartTotalHTML = writeCart.outerHTML;
cartTotal.innerHTML = cartTotalHTML;
console.log(cartTotal);
}
}
<h3>Search for items in the menu below to add to cart</h3>
<form id="searchMenu">
<input type="search" id="query" name="q" placeholder="Search Menu..."></inpuut>
<input type = "Submit" name= "search" id="addItem" ></input>
</form>
<h4>Your cart: </h4>
<div class="Cart">
<div id="showCart"></div>
</div>
<script src="Script.js"></script>
<h4>Cart</h4>
<button id='addCartButton' class="Cart">Add Cart</button>
<div class="ShowCart">
<div id="totalCart"></div>
</div>
<script src="Script.js"></script>

why i can't show data i want when user clicks on button

i am making a simple search autocomplete app which search cities and it's information.
the problem is when clicked on suggestion i want that cities information in different html element.
so my javascript code is:
let search=document.getElementById("search");
let searchlist=document.getElementById("searchlist");
search.addEventListener("input",()=>searchcities(search.value));
const searchcities=async searchtext=>{
var res= await fetch("in.json");
const cities=await res.json();
let matches=cities.filter(city=>{
const regex=new RegExp(`^${searchtext}`,'gi');
return city.city.match(regex);
});
if(searchtext.length===0){
matches=[];
searchlist.innerHTML="";
}
outputHTML(matches);
};
function outputHTML(matches){
if(matches.length>0){
const html=matches.map(match=>`
<button class="card" >
<h4>${match.city}<span class="state ">(${match.admin})</span></h4>
<small>Latitude: ${match.lat}<br>longitude:${match.lng}</small>
</button>
`).join("");
searchlist.innerHTML=html;
document.querySelector(".card").addEventListener("click",showresult)
function showresult(match){
let result=document.querySelector("#finalresult");
const show=`
<div class="result">
<h4>${match.city}<span class="state ">(match.admin})</span></h4>
<small>Latitude: ${match.lat}<br>longitude:${match.lng}</small>
</div>
`;
result.innerHTML=show;
console.log(result);
}
}
}
i want this function to work :
function showresult(match){
let result=document.querySelector("#finalresult");
const show=`
<div class="result">
<h4>${match.city}<span class="state ">(match.admin})</span></h4>
<small>Latitude: ${match.lat}<br>longitude:${match.lng}</small>
</div>
`;
result.innerHTML=show;
console.log(result);
}
}
but it is giving me undefined data. I don't know what to do .
the structure of json file is like this:
{
"city": "Mumbai",
"admin": "Maharashtra",
"country": "India",
"population_proper": "12691836",
"iso2": "IN",
"capital": "admin",
"lat": "18.987807",
"lng": "72.836447",
"population": "18978000"
}
thanks for helping.
You're making it yourself to complex for what it actually is. Have you thought about data attributes? Here's an example:
//Fetch function
const searchCities = async searchText => {
if(searchText == null) return;
let matches;
if(searchText.length < 1) matches = []; //current behaviour will set it to no matches when your removed everything from the input
else {
const res = await fetch('js/in.json');
const cities = await res.json();
matches = await cities.filter(city=>{
const regex=new RegExp(`^${searchText}`,'gi');
return city.city.match(regex);
});
}
outputHTML(matches);
};
//Inner function
const outputHTML = (matches) => {
if(matches == null) return;
let html = '<p>no matches</p>';
if(matches.length !== 0) {
html = matches.map(match => `
<button class="card" data-city="${match.city}" data-admin="${match.admin}" data-lat="${match.lat}" data-lng="${match.lng}">
<h4>${match.city}<span class="state ">(${match.admin})</span></h4>
<small>Latitude: ${match.lat}<br>longitude:${match.lng}</small>
</button>
`).join('');
}
const searchlist = document.getElementById("searchlist");
searchlist.innerHTML = html;
const cards = document.querySelectorAll(".card");
cards.forEach(card => card.addEventListener("click", showResult));
};
//Click card function
const showResult = (event) => {
const card = event.currentTarget;
const result = document.querySelector('#finalresult');
const cardData = card.dataset;
const show = `
<div class="result">
<h4>${cardData.city}<span class=""state">${cardData.admin}</span></h4>
<small>Latidude: ${cardData.lat}<br>longitude:${cardData.lng}</small>
</div>
`;
result.innerHTML = show;
};
//Setup
const setup = () => {
const search = document.getElementById("search");
search.addEventListener("input",()=>searchCities(search.value));
};
//Load
window.addEventListener('load', setup);
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Indian cities</title>
<script src="js/main.js"></script>
</head>
<body>
<div class="indian-flag">
<div class="1"></div>
<div class="2"></div>
<div class="3"></div>
</div>
<div class="head">CITIES lookup</div>
<input type="text" name="" id="search" class="input" placeholder="Enter city name...">
<div id="searchlist"></div>
<div id="finalresult"></div>
</body>
</html>

Categories