The method of removing products by their name does not work. I'm trying to delete using buttDelete.addEventListener but the deletion does not happen.
The logic of the deleteProductByName method is that when the name of product is received from input nameDelete it is checked the same products in shop.products array, then when the button delete is press (buttDelete), the product is deleted from the array and correspondingly from the table too, if the field is empty, then output alert that you need to fill out the field.
Help please fix that
//Product Creation Class
class Product {
constructor(name, count, price) {
this.name = name;
this.count = count;
this.price = price;
}
}
// Сlass where products are recorded
class Shop {
constructor() {
this.products = [];
}
//method for adding a product
addProduct(newProduct) {
this.products.push(newProduct);
}
//method for remove product by name
deleteProductByName(productName) {
let i = this.products.length;
while (i--) {
if (productName === this.products[i].name) {
this.products.splice(i, 1);
}
}
}
// get total price by all products
get totalProductsPrice() {
return this.products.map(product => product.price).reduce((p, c) => p + c);
}
// method to draw the table with product property (
// name, count, price)
show() {
const rows = document.querySelectorAll("#shop .data");
for (let i = rows.length - 1; i >= 0; i--) {
const e = rows.item(i);
e.parentNode.removeChild(e);
}
const table = document.getElementById("shop");
for (let i = 0; i < this.products.length; i++) {
//create table
table.innerHTML += `<tbody><tr class="data"><td>${this.products[i].name}</td>
<td>${this.products[i].price}</td>
<td>${this.products[i].count}</td></tr></tbody>`;
}
//show total price by all products
table.innerHTML += `<tfoot><tr id="total-price"><td colspan="3">Total price:
${shop.totalProductsPrice}</td></tr></tfoot>`;
}
}
// add new product by click
const formAdd = document.forms[0];
const inputsAdd = formAdd.elements;
const buttAdd = formAdd.elements[3];
buttAdd.addEventListener('click', (e) => {
e.preventDefault();
shop.addProduct(new Product(inputsAdd[0].value, parseInt(inputsAdd[2].value),
parseInt(inputsAdd[1].value)));
shop.show();
}, false);
// delete product by name after click
const formDelete = document.forms[1];
const nameDelete = formDelete.elements[0];
const buttDelete = formDelete.elements[1];
buttDelete.addEventListener('click', (e) => {
e.preventDefault();
shop.deleteProductByName(nameDelete.value);
shop.show();
}, false);
let shop = new Shop();
shop.addProduct(new Product("product 1", 1, 2000));
shop.show();
<div class="Shop">
<div class="add-product">
<h1>Add product</h1>
<form id="addForm">
<label for="name" >Name of product</label>
<input type="text" id="name" class="input-product">
<label for="price">Price of product</label>
<input type="text" id="price" class="input-product">
<label for="count">Count of product</label>
<input type="text" id="count" class="input-product">
<button id="add">Add</button>
</form>
</div>
<div class="product-table">
<h2>Products</h2>
<form id="delete-form">
<label for="name-delete">Delete product by name</label>
<input type="text" id="name-delete" class="input-delete">
<button id="delete" type="button">Delete</button>
</form>
<table id="shop">
<caption>Products that are available in the store</caption>
<tr>
<th>Name:</th>
<th id="filter">Price:</th>
<th>Count:</th>
</tr>
</table>
</div>
</div>
Then I would use a console.log() or a debugger on
//method for remove product by name
deleteProductByName(productName) {
let i = this.products.length;
while (i--) {
console.log("productName " + productName + "this.products[i].name" + this.products[i].name);
if (productName === this.products[i].name) {
this.products.splice(i, 1);
}
}
}
to see if you comparing the same names. To make sure your if statement is working as expected.
Related
my original question got answered but I realize that every time I try to push user data in the arrays it wouldn't allow me to do is there any another to append data to arrays or is the push method the only way. or should i create a new array................................................................
"use strict"
const names = ["Ben", "Joel", "Judy", "Anne"];
const scores = [88, 98, 77, 88];
const $ = selector => document.querySelector(selector);
const addScore = () => {
// get user entries
const name = $("#name").value;
const score = parseInt($("#score").value);
let isValid = true;
// check entries for validity
if (name == "") {
$("#name").nextElementSibling.textContent = "This field is required.";
isValid = false;
} else {
$("#name").nextElementSibling.textContent = "";
}
if (isNaN(score) || score < 0 || score > 100) {
$("#score").nextElementSibling.textContent = "You must enter a valid score.";
isValid = false;
} else {
$("#score").nextElementSibling.textContent = "";
}
if (isValid) {
names.push("#name");
scores.push("#score");
names[names.length] = name;
scores[scores.length] = score;
$("#name").value = "";
$("#score").value = "";
}
$("#name").focus();
};
// display scores
const displayScores = () => {
for (let i = 0; i < names.length; i++) {
document.getElementById("scores_display").textContent += names[i] + " = " +
scores[i] +
"\n";
}
};
document.addEventListener("DOMContentLoaded", () => {
$("#add").addEventListener("click", addScore);
$("#display_scores").addEventListener("click", displayScores())
$("#name").focus();
});
<main>
<h1>Use a Test Score array</h1>
<div>
<label for="name">Name:</label>
<input type="text" id="name">
<span></span>
</div>
<div>
<label for="score">Score:</label>
<input type="text" id="score">
<span></span>
</div>
<div>
<label> </label>
<input type="button" id="add" value="Add to Array">
<input type="button" id="display_scores" value="Display Scores">
</div>
<div>
<textarea id="scores_display"></textarea>
</div>
</main>
All my previous notes were incorrect. Your adhoc $ const threw me off! My apologies.
The issue was you weren't calling displayScores() after updating the array. Plus, I added a line to that function to clear the existing text before looping through your data.
"use strict"
const names = ["Ben", "Joel", "Judy", "Anne"];
const scores = [88, 98, 77, 88];
const $ = selector => document.querySelector(selector);
const addScore = () => {
// get user entries
const name = $("#name").value;
const score = parseInt($("#score").value);
let isValid = true;
// check entries for validity
if (name == "") {
$("#name").nextElementSibling.textContent = "This field is required.";
isValid = false;
} else {
$("#name").nextElementSibling.textContent = "";
}
if (isNaN(score) || score < 0 || score > 100) {
$("#score").nextElementSibling.textContent = "You must enter a valid score.";
isValid = false;
} else {
$("#score").nextElementSibling.textContent = "";
}
if (isValid) {
names.push("#name");
scores.push("#score");
names[names.length] = name;
scores[scores.length] = score;
$("#name").value = "";
$("#score").value = "";
// add to the textarea
displayScores()
}
$("#name").focus();
};
// display scores
const displayScores = () => {
document.getElementById("scores_display").textContent = "";
for (let i = 0; i < names.length; i++) {
document.getElementById("scores_display").textContent += names[i] + " = " +
scores[i] +
"\n";
}
};
document.addEventListener("DOMContentLoaded", () => {
$("#add").addEventListener("click", addScore);
$("#display_scores").addEventListener("click", displayScores())
$("#name").focus();
});
<main>
<h1>Use a Test Score array</h1>
<div>
<label for="name">Name:</label>
<input type="text" id="name">
<span></span>
</div>
<div>
<label for="score">Score:</label>
<input type="text" id="score">
<span></span>
</div>
<div>
<label> </label>
<input type="button" id="add" value="Add to Array">
<input type="button" id="display_scores" value="Display Scores">
</div>
<div>
<textarea rows="6" id="scores_display"></textarea>
</div>
</main>
I am building a library app that stores user books. It should take user input, store it into an array and then display it on the page.
If I manually enter a few object instances in the array, the displayed values are as they should be (eg.title: harry potter, author: JK Rowling, etc), but my object instances created from user input are displayed like so:
function() { return this.title + " by " + this.author + ", " + this.pages + " pages, " + this.read + "."; }
Also, only one instance of object is created even though I've set an event listener on the button.
What am I doing wrong?
document.addEventListener("DOMContentLoaded", () => {
document.getElementById('submit').addEventListener("click", addBookToLibrary);
})
let myLibrary = [];
function Book(title,author,pages,read) {
this.title = title;
this.author = author;
this.pages = pages;
this.read = read;
this.info = function() {
return this.title + " by " + this.author + ", " + this.pages + " pages, " + this.read + ".";
}
}
function addBookToLibrary() {
let newBook = new Book();
newBook.title = document.getElementById("title").value;
newBook.author = document.getElementById("author").value;
newBook.pages = document.getElementById("pages").value;
newBook.read = document.getElementById("read").value;
myLibrary.push(newBook);
document.querySelector("form").reset(); // clear the form for the next entries
}
addBookToLibrary();
//loop through an array and display each book
function displayBooks() {
for (let i=0; i<myLibrary.length; i++) {
const booksDisplay = document.getElementById("books-display");
const cardBook = document.createElement('div');
cardBook.classList.add("grid-item");
cardBook.innerHTML += Object.values(myLibrary[i]).join(" ");
booksDisplay.appendChild(cardBook);
}
}
displayBooks();
<body>
<header>
</header>
<main>
<div id="page-wrapper">
<form id="new-book">
<label for="title">Title</label><br>
<input type="text" id="title" value=""/><br><br>
<label for="author">Author</label><br>
<input type="text" id="author" value=""/><br><br>
<label for="pages">Pages</label><br>
<input type="text" id="pages" value=""/><br><br>
<label for="read">Read</label><br>
<input type="checkbox" id="read" value=""/><br><br>
<button id="submit">Click to add</button>
</form> <br><br>
<div id="books-display"></div>
</div>
</main>
</body>
There are several issues. First, you are not preventing the page reload on the form, and therefore, any data that has been set by js will be lost upon page reload. You need to add e.preventDefault() to the addBookToLibrary function.
Secondly, you need to call the displayBooks function when a new record is added in order to re-render the updated list. You can just put the function call inside addBookToLibrary function.
Here is the example:
function addBookToLibrary(e) {
e.preventDefault()
let newBook = new Book();
newBook.title = document.getElementById("title").value;
newBook.author = document.getElementById("author").value;
newBook.pages = document.getElementById("pages").value;
newBook.read = document.getElementById("read").value;
myLibrary.push(newBook);
document.querySelector("form").reset(); // clear the form for the next entries
displayBooks();
}
Third, if you want to print the values, you can just call the info function, no need to use Object.values(...) . For example, here myLibrary[i] is a Book object. And since you have already declared a method info inside the Book class, you can just call the method and render it according to that.
Replace
Object.values(myLibrary[i]).join(" ");
With
myLibrary[i].info();
Example:
//loop through an array and display each book
function displayBooks() {
const booksDisplay = document.getElementById("books-display");
booksDisplay.innerHTML = "";
for (let i=0; i<myLibrary.length; i++) {
const cardBook = document.createElement('div');
cardBook.classList.add("grid-item");
cardBook.innerHTML += myLibrary[i].info();
booksDisplay.appendChild(cardBook);
}
}
Finally, remove the direct call of addBookToLibrary and displayBooks. addBookToLibrary should only be called when uses submit the form and displayBooks should only be called when a new record is added via form submission.
Here is the complete setup
document.addEventListener("DOMContentLoaded", () => {
document.getElementById('submit').addEventListener("click", addBookToLibrary);
})
let myLibrary = [];
function Book(title,author,pages,read) {
this.title = title;
this.author = author;
this.pages = pages;
this.read = read;
this.info = function() {
return this.title + " by " + this.author + ", " + this.pages + " pages, " + this.read + ".";
}
}
function addBookToLibrary(e) {
e.preventDefault()
let newBook = new Book();
newBook.title = document.getElementById("title").value;
newBook.author = document.getElementById("author").value;
newBook.pages = document.getElementById("pages").value;
newBook.read = document.getElementById("read").value;
myLibrary.push(newBook);
document.querySelector("form").reset(); // clear the form for the next entries
displayBooks();
}
//loop through an array and display each book
function displayBooks() {
const booksDisplay = document.getElementById("books-display");
booksDisplay.innerHTML = ""; //clear the dom first
for (let i=0; i<myLibrary.length; i++) {
const cardBook = document.createElement('div');
cardBook.classList.add("grid-item");
cardBook.innerHTML += myLibrary[i].info();
booksDisplay.appendChild(cardBook);
}
}
<main>
<div id="page-wrapper">
<form id="new-book">
<label for="title">Title</label><br>
<input type="text" id="title" value=""/><br><br>
<label for="author">Author</label><br>
<input type="text" id="author" value=""/><br><br>
<label for="pages">Pages</label><br>
<input type="text" id="pages" value=""/><br><br>
<label for="read">Read</label><br>
<input type="checkbox" id="read" value=""/><br><br>
<button id="submit">Click to add</button>
</form> <br><br>
<div id="books-display"></div>
</div>
</main>
You can save yourself some time writing out all those element ids and property names in the Book function by using a new FormData object.
Some other changes:
Move the info() method to a prototype of Book. Then when you need to serialize the data it won't be included as a property
You need a boolean true/false based on check state of a checkbox not it's value
Use a submit event listener on the form rather than click on the button. Within the callback this will then be the form element to simplify things like this.reset()
initDemo()
document.getElementById('new-book').addEventListener("submit", addBookToLibrary);
let myLibrary = [];
function Book(formData) {
const checkBoxes = ['read'];
for (let [k, v] of formData.entries()) {
this[k] = v
}
// boolean values for checkboxes
checkBoxes.forEach(k => this[k] = this[k] !== undefined);
}
Book.prototype.info = function() {
return this.title + " by " + this.author + ", " + this.pages + " pages, " + this.read + ".";
}
function addBookToLibrary(e) {
e.preventDefault();
let newBook = new Book(new FormData(this));
console.clear()
console.log(JSON.stringify(newBook, null, 4));
myLibrary.push(newBook);
this.reset(); // clear the form for the next entries
displayBooks();
}
//loop through an array and display each book
function displayBooks() {
const booksDisplay = document.getElementById("books-display");
booksDisplay.innerHTML = ""; //clear the dom first
for (let i = 0; i < myLibrary.length; i++) {
const cardBook = document.createElement('div');
cardBook.classList.add("grid-item");
cardBook.innerHTML += myLibrary[i].info();
booksDisplay.appendChild(cardBook);
}
}
function initDemo(){
document.querySelectorAll('[data-value').forEach(el=>el.value = el.dataset.value)
}
<main >
<div id="page-wrapper">
<form id="new-book">
<label for="title">Title</label><br>
<input type="text" name="title" id="title" data-value="Foo Goes to Bar" /><br><br>
<label for="author">Author</label><br>
<input type="text" name="author" id="author" data-value="Mr Foo" /><br><br>
<label for="pages">Pages</label><br>
<input type="text" name="pages" id="pages" data-value="3" /><br><br>
<label for="read">Read</label><br>
<input type="checkbox" name="read" id="read" value="read" /><br><br>
<button id="submit">Click to add</button>
</form> <br><br>
<div id="books-display"></div>
</div>
</main>
When the listener "buttAdd.addEventListener" for the add method is triggered: , first this condition works several times(works with the second addition):
if (inputsAdd [0].value ===""||inputsAdd [1].value ===""||inputsAdd [2]
.value === "")
{alert ("fill all fields");}
It works when the fields are not empty, and then the product is added. And if you click on the add button with empty fields, then the product that was added earlier - will be lost. The same story awith the method, delete. Help me please to fix it
//Product Creation Class
class Product {
constructor(name, count, price) {
this.name = name;
this.count = count;
this.price = price;
}
}
Product.SORT_ORDER_ASC = 1;
Product.SORT_ORDER_DESC = -1;
// Сlass where products are recorded
class Shop {
constructor() {
this.products = [];
this.formAdd = document.forms[0];
this.inputsAdd = this.formAdd.elements;
this.buttAdd = this.formAdd.elements[3];
this.formDelete = document.forms[1];
this.nameDelete = this.formDelete.elements[0];
this.buttDelete = this.formDelete.elements[1];
}
//method for adding a product
addProduct(newProduct) {
this.products.push(newProduct);
}
//method for remove product by name
deleteProductByName(productName) {
let i = this.products.length;
while (i--) {
if (productName === this.products[i].name) {
this.products.splice(i, 1);
}
}
}
// get total price by all products
get totalProductsPrice() {
return this.products.map(product => product.price).reduce((p, c) => p + c);
}
//method for sorting the product at its price
sortProductsByPrice(sortOrder) {
const sorted = this.products.sort((a, b) => {
return a.price > b.price ? sortOrder : -sortOrder;
});
this.products = sorted;
}
// method to draw the table with product property (
// name, count, price)
show() {
// add new product by click
this.buttAdd.addEventListener('click', (e) => {
e.preventDefault();
if (this.inputsAdd[0].value === "" || this.inputsAdd[1].value === "" || this.inputsAdd[2].value === "") {
alert("fill all fields");
} else {
this.addProduct(new Product(this.inputsAdd[0].value, parseInt(this.inputsAdd[2].value),
parseInt(this.inputsAdd[1].value)));
this.show();
this.inputsAdd[0].value = "";
this.inputsAdd[1].value = "";
this.inputsAdd[2].value = "";
}
}, false);
// delete product by name after click
this.buttDelete.addEventListener('click', (e) => {
e.preventDefault();
if (this.nameDelete.value === "") {
alert("write a name of product what you want to delete");
} else {
this.deleteProductByName(this.nameDelete.value);
this.show();
this.nameDelete.value = "";
}
}, false);
const rows = document.querySelectorAll("#shop .data");
for (let i = rows.length - 1; i >= 0; i--) {
const e = rows.item(i);
e.parentNode.removeChild(e);
}
const table = document.getElementById("shop");
const tFoot = table.querySelector('tfoot');
if (tFoot) tFoot.remove();
for (let i = 0; i < this.products.length; i++) {
//create table
table.innerHTML += `<tbody><tr class="data"><td>${this.products[i].name}</td>
<td>${this.products[i].price}</td>
<td>${this.products[i].count}</td></tr></tbody>`;
}
//show total price by all products
table.innerHTML += `<tfoot><tr><td colspan="3" id="total-price">Total price:
${this.totalProductsPrice}</td></tr></tfoot>`;
//filter products by price
document.addEventListener("click", (e) => {
let elem = e.target;
if (elem.id === "filter") {
this.sortProductsByPrice(Product.SORT_ORDER_ASC);
this.show();
}
}, false);
console.log(this.products);
}
}
let shop = new Shop();
shop.addProduct(new Product("product", 1, 2000));
shop.addProduct(new Product("product1", 2, 500));
shop.addProduct(new Product("product2", 3, 1000));
shop.show();
<div class="Shop">
<div class="add-product">
<h1>Add product</h1>
<form id="addForm">
<label for="name" >Name of product</label>
<input type="text" id="name" class="input-product">
<label for="price">Price of product</label>
<input type="text" id="price" class="input-product">
<label for="count">Count of product</label>
<input type="text" id="count" class="input-product">
<button id="add" type="button">Add</button><!-- *** -->
</form>
</div>
<div class="product-table">
<h2>Products</h2>
<form id="delete-form">
<label for="name-delete">Delete product by name</label>
<input type="text" id="name-delete" class="input-delete">
<button id="delete" type="button">Delete</button>
</form>
<table id="shop">
<caption>Products that are available in the store</caption>
<tr>
<th>Name:</th>
<th id="filter">Price:</th>
<th>Count:</th>
</tr>
</table>
</div>
</div>
See, you're defining let shop = new Shop() and then use this variable in your Shop class, like shop.show(). I strongly recommend you to use this keyword instead of scoped variable (valid for all other shop usage entries).
Now, about
works several times
I assume, that when you call the show() method it registers more event listeners some time. I mean, you call show - it creates new event listeners + sometimes calls itself (huh, it is pretty risky). I suggest you to move listeners declaration to the constructor - so they will be instantinated once (but that will require keeping DOM nodes). Also it would be nice to split your show fucntion to several smaller functions and get rid of self function emit (it will reduce complexity).
In the sortProductsByPrice (sortOrder) method, sorting does not work when I delete or add new products, sorting works only for products that are in the this.products array by default.
(Products are sorted by clicking <th> Price: </ th>).
It is necessary that sorting can use too after removal / addition of goods.
//Product Creation Class
class Product {
constructor(name, count, price) {
this.name = name;
this.count = count;
this.price = price;
}
}
Product.SORT_ORDER_ASC = 1;
Product.SORT_ORDER_DESC = -1;
// Сlass where products are recorded
class Shop {
constructor() {
this.products = [];
}
//method for adding a product
addProduct(newProduct) {
this.products.push(newProduct);
}
//method for remove product by name
deleteProductByName(productName) {
let i = this.products.length;
while (i--) {
if (productName === this.products[i].name) {
this.products.splice(i, 1);
}
}
}
// get total price by all products
get totalProductsPrice() {
return this.products.map(product => product.price).reduce((p, c) => p + c);
}
//method for sorting the product at its price
sortProductsByPrice(sortOrder) {
const sorted = this.products.sort((a, b) => {
return a.price > b.price ? sortOrder : -sortOrder;
});
this.products = sorted;
}
// method to draw the table with product property (
// name, count, price)
show() {
const formAdd = document.forms[0];
const inputsAdd = formAdd.elements;
const buttAdd = formAdd.elements[3];
const formDelete = document.forms[1];
const nameDelete = formDelete.elements[0];
const buttDelete = formDelete.elements[1];
const priceFilter = document.getElementById("filter");
// add new product by click
buttAdd.addEventListener('click', (e) => {
e.preventDefault();
shop.addProduct(new Product(inputsAdd[0].value, parseInt(inputsAdd[2].value),
parseInt(inputsAdd[1].value)));
shop.show();
}, false);
// delete product by name after click
buttDelete.addEventListener('click', (e) => {
e.preventDefault();
shop.deleteProductByName(nameDelete.value);
shop.show();
}, false);
const rows = document.querySelectorAll("#shop .data");
for (let i = rows.length - 1; i >= 0; i--) {
const e = rows.item(i);
e.parentNode.removeChild(e);
}
const table = document.getElementById("shop");
const tFoot = table.querySelector('tfoot');
if (tFoot) tFoot.remove();
for (let i = 0; i < this.products.length; i++) {
//create table
table.innerHTML += `<tbody><tr class="data"><td>${this.products[i].name}</td>
<td>${this.products[i].price}</td>
<td>${this.products[i].count}</td></tr></tbody>`;
}
//show total price by all products
table.innerHTML += `<tfoot><tr><td colspan="3" id="total-price">Total price:
${shop.totalProductsPrice}</td></tr></tfoot>`;
priceFilter.addEventListener("click", (e) => {
shop.sortProductsByPrice(Product.SORT_ORDER_ASC);
shop.show();
}, false);
}
}
let shop = new Shop();
shop.addProduct(new Product("product", 1, 2000));
shop.addProduct(new Product("product1", 2, 500));
shop.addProduct(new Product("product2", 3, 1000));
shop.show();
console.log(shop.products);
<div class="Shop">
<div class="add-product">
<h1>Add product</h1>
<form id="addForm">
<label for="name" >Name of product</label>
<input type="text" id="name" class="input-product">
<label for="price">Price of product</label>
<input type="text" id="price" class="input-product">
<label for="count">Count of product</label>
<input type="text" id="count" class="input-product">
<button id="add">Add</button>
</form>
</div>
<div class="product-table">
<h2>Products</h2>
<form id="delete-form">
<label for="name-delete">Delete product by name</label>
<input type="text" id="name-delete" class="input-delete">
<button id="delete" type="button">Delete</button>
</form>
<table id="shop">
<caption>Products that are available in the store</caption>
<tr>
<th>Name:</th>
<th id="filter">Price:</th>
<th>Count:</th>
</tr>
</table>
</div>
</div>
It is necessary that sorting can use too after removal / addition of goods
The sorting is not working after addition/removal because you are calling show() method after adding/removing element, which will redraw the whole HTML, without attaching any events to it, so the originally attached event handlers will be unbound.
You need to attach the event handlers in your show() method to resolve this problem.
And there's no need to return the sorted array in your method, the original this.products will be sorted in place.
So there's no need to declare sorted array, and return it, just write the this.products.sort() code it will sort the array.
sortProductsByPrice(sortOrder) {
this.products.sort((a, b) => {
return a.price > b.price ? sortOrder : -sortOrder;
});
}
Demo:
//Product Creation Class
class Product {
constructor(name, count, price) {
this.name = name;
this.count = count;
this.price = price;
}
}
Product.SORT_ORDER_ASC = 1;
Product.SORT_ORDER_DESC = -1;
// Сlass where products are recorded
class Shop {
constructor() {
this.products = [];
}
//method for adding a product
addProduct(newProduct) {
this.products.push(newProduct);
}
//method for remove product by name
deleteProductByName(productName) {
let i = this.products.length;
while (i--) {
if (productName === this.products[i].name) {
this.products.splice(i, 1);
}
}
}
// get total price by all products
get totalProductsPrice() {
return this.products.map(product => product.price).reduce((p, c) => p + c);
}
//method for sorting the product at its price
sortProductsByPrice(sortOrder) {
this.products.sort((a, b) => {
return a.price > b.price ? sortOrder : -sortOrder;
});
}
// method to draw the table with product property (
// name, count, price)
show() {
const rows = document.querySelectorAll("#shop .data");
for (let i = rows.length - 1; i >= 0; i--) {
const e = rows.item(i);
e.parentNode.removeChild(e);
}
const table = document.getElementById("shop");
const tFoot = table.querySelector('tfoot');
if (tFoot) tFoot.remove();
for (let i = 0; i < this.products.length; i++) {
//create table
table.innerHTML += `<tbody><tr class="data"><td>${this.products[i].name}</td>
<td>${this.products[i].price}</td>
<td>${this.products[i].count}</td></tr></tbody>`;
}
//show total price by all products
table.innerHTML += `<tfoot><tr><td colspan="3" id="total-price">Total price:
${shop.totalProductsPrice}</td></tr></tfoot>`;
}
}
// add new product by click
const formAdd = document.forms[0];
const inputsAdd = formAdd.elements;
const buttAdd = formAdd.elements[3];
buttAdd.addEventListener('click', (e) => {
e.preventDefault();
shop.addProduct(new Product(inputsAdd[0].value, parseInt(inputsAdd[2].value),
parseInt(inputsAdd[1].value)));
shop.show();
}, false);
// delete product by name after click
const formDelete = document.forms[1];
const nameDelete = formDelete.elements[0];
const buttDelete = formDelete.elements[1];
buttDelete.addEventListener('click', (e) => {
e.preventDefault();
shop.deleteProductByName(nameDelete.value);
shop.show();
}, false);
let shop = new Shop();
shop.addProduct(new Product("product", 1, 2000));
shop.addProduct(new Product("product1", 2, 500));
shop.addProduct(new Product("product2", 3, 1000));
shop.show();
const priceFilter = document.getElementById("filter");
//filter products by price
priceFilter.addEventListener("click", (e) => {
shop.sortProductsByPrice(Product.SORT_ORDER_ASC);
shop.show();
}, false);
<div class="Shop">
<div class="add-product">
<h1>Add product</h1>
<form id="addForm">
<label for="name">Name of product</label>
<input type="text" id="name" class="input-product">
<label for="price">Price of product</label>
<input type="text" id="price" class="input-product">
<label for="count">Count of product</label>
<input type="text" id="count" class="input-product">
<button id="add">Add</button>
</form>
</div>
<div class="product-table">
<h2>Products</h2>
<form id="delete-form">
<label for="name-delete">Delete product by name</label>
<input type="text" id="name-delete" class="input-delete">
<button id="delete" type="button">Delete</button>
</form>
<table id="shop">
<caption>Products that are available in the store</caption>
<tr>
<th>Name:</th>
<th id="filter">Price:</th>
<th>Count:</th>
</tr>
</table>
</div>
</div>
I want to transfer the value from three inputs: "name", "counter" and "price" to the array "products" that I then display in the table. But when I add them using the buttAdd.addEventListener handler, the new elements are not displayed in the table Help fix this
//Product Creation Class
class Product {
constructor(name, count, price) {
this.name = name;
this.count = count;
this.price = price;
}
}
// Сlass where products are recorded
class Shop {
constructor(products) {
this.products = [];
}
//method for adding a product
addProduct(newProduct) {
this.products.push(newProduct);
}
show() {
const rows = document.querySelectorAll("#shop .data");
for (let i = rows.length - 1; i >= 0; i--) {
const e = rows.item(i);
e.parentNode.removeChild(e);
}
const table = document.getElementById("shop");
for (let i = 0; i < this.products.length; i++) {
//create table
table.innerHTML += `<tr class="data"><td>${this.products[i].name}</td>
<td>${this.products[i].price}</td>
<td>${this.products[i].count}</td></tr>`;
}
}
}
const formAdd = document.forms[0];
const inputsAdd = formAdd.elements;
const buttAdd = formAdd.elements[3];
buttAdd.addEventListener('click', (e) => {
for (let i = 0; i <= 3; i++) {
shop.addProduct(inputsAdd[i].value);
}
shop.show();
}, false);
let shop = new Shop();
shop.addProduct(new Product("product 1", 1, 2000));
shop.show();
<form id="addForm">
<label for="name" >Name of product</label>
<input type="text" id="name" class="input-product">
<label for="price">Price of product</label>
<input type="text" id="price" class="input-product">
<label for="count">Count of product</label>
<input type="text" id="count" class="input-product">
<button id="add">Add</button>
</form>
<table id="shop">
<caption>Products that are available in the store</caption>
<tr>
<th>Name:</th>
<th id="filter">Price:</th>
<th>Count:</th>
</tr>
</table>
Below are the errors in your code.
Your for loop inside buttAdd.addEventListener is not correct.condition <=3 will iterate 4 time while input fields are only 3.
shop.addProduct(inputsAdd[i].value); is wrong because addProduct method of shop class required Product class object so you need to create new Product class object and set the values of input through constructor.
This is the correct way:
shop.addProduct(new Product(inputsAdd[0].value,inputsAdd[1].value,inputsAdd[2].value));
Here is the running snippet
//Product Creation Class
class Product {
constructor(name, count, price) {
this.name = name;
this.count = count;
this.price = price;
}
}
// Сlass where products are recorded
class Shop {
constructor(products) {
this.products = [];
}
//method for adding a product
addProduct(newProduct) {
this.products.push(newProduct);
}
show() {
const rows = document.querySelectorAll("#shop .data");
for (let i = rows.length - 1; i >= 0; i--) {
const e = rows.item(i);
e.parentNode.removeChild(e);
}
const table = document.getElementById("shop");
for (let i = 0; i < this.products.length; i++) {
//create table
table.innerHTML += `<tr class="data"><td>${this.products[i].name}</td>
<td>${this.products[i].price}</td>
<td>${this.products[i].count}</td></tr>`;
}
}
}
const formAdd = document.forms[0];
const inputsAdd = formAdd.elements;
const buttAdd = formAdd.elements[3];
//console.log(buttAdd);
buttAdd.addEventListener('click', (e) => {
e.preventDefault();
shop.addProduct(new Product(inputsAdd[0].value,parseInt(inputsAdd[1].value),inputsAdd[2].value));
shop.show();
}, false);
let shop = new Shop();
shop.addProduct(new Product("product 1", 1, 2000));
shop.show();
<form id="addForm">
<label for="name" >Name of product</label>
<input type="text" id="name" class="input-product">
<label for="price">Price of product</label>
<input type="text" id="price" class="input-product">
<label for="count">Count of product</label>
<input type="text" id="count" class="input-product">
<button id="add">Add</button>
</form>
<table id="shop">
<caption>Products that are available in the store</caption>
<tr>
<th>Name:</th>
<th id="filter">Price:</th>
<th>Count:</th>
</tr>
</table>
Your addProduct() method takes in a Product object as input, but in click listener you are passing form field input values without forming a object
//Product Creation Class
class Product {
constructor(name, count, price) {
this.name = name;
this.count = count;
this.price = price;
}
}
// Сlass where products are recorded
class Shop {
constructor(products) {
this.products = [];
}
//method for adding a product
addProduct(newProduct) {
this.products.push(newProduct);
}
show() {
const rows = document.querySelectorAll("#shop .data");
for (let i = rows.length - 1; i >= 0; i--) {
const e = rows.item(i);
e.parentNode.removeChild(e);
}
const table = document.getElementById("shop");
for (let i = 0; i < this.products.length; i++) {
//create table
table.innerHTML += `<tr class="data"><td>${this.products[i].name}</td>
<td>${this.products[i].price}</td>
<td>${this.products[i].count}</td></tr>`;
}
}
}
const formAdd = document.forms[0];
const inputsAdd = formAdd.elements;
const buttAdd = formAdd.elements[3];
buttAdd.addEventListener('click', (e) => {
e.preventDefault();
let tempProduct = new
Product(inputsAdd[0].value,parseInt(inputsAdd[1].value),parseInt(inputsAdd[2].value));
shop.addProduct(tempProduct);
shop.show();
}, false);
let shop = new Shop();
shop.addProduct(new Product("product 1", 1, 2000));
shop.show();
<form id="addForm">
<label for="name" >Name of product</label>
<input type="text" id="name" class="input-product">
<label for="price">Price of product</label>
<input type="text" id="price" class="input-product">
<label for="count">Count of product</label>
<input type="text" id="count" class="input-product">
<button id="add">Add</button>
</form>
<table id="shop">
<caption>Products that are available in the store</caption>
<tr>
<th>Name:</th>
<th id="filter">Price:</th>
<th>Count:</th>
</tr>
</table>