Array.find to update a value in a nested array - javascript

I created a basket in JavaScript, it works perfectly except for one thing:
When we add products to the basket, we select a quantity and everything goes well, but if we click again to add the same product, instead of modifying the quantity of the product, the same product is added to the localStorage.
To avoid this problem, I have to search for the product in the localStorage with the Array.find() method, if the product exists, I modify the quantity, otherwise I add it. But I don't know how to do it the right way yet
let basket = JSON.parse(localStorage.getItem('monPanier')) || [];
let wishlist = JSON.parse(localStorage.getItem('myWishList')) || [];
let totalBasket = 0;
let nbrArticles;
let nbrWishlist;
function addBasket()
{
let quantity_cart = $(".input_quantity"+$(this).data("id")).val();
let name_article_cart = $(this).data("name");
let idArticle = parseInt(this.id.replace("add_basket_btn_",""));
let price_cart = $(this).data("price");
let total_price_cart = (quantity_cart * price_cart);
let newBasket = [idArticle,quantity_cart,name_article_cart,price_cart,total_price_cart];
basket.push(newBasket);
saveStorageBasket();
loadStorageBasket();
showBasket();
calculeNbrArticle();
console.log(newBasket);
}
function addWishlist()
{
let name_article_wishlist = $(this).data("name");
let idArticle = parseInt(this.id.replace("add_wishlist_btn_",""));
let price_article_wishlist = $(this).data("price");
let newWishlist = [idArticle,name_article_wishlist,price_article_wishlist];
wishlist.push(newWishlist);
saveStorageWishlist();
loadStorageWishlist();
showWishList();
calculeNbrWishlist();
}
function showBasket() {
//vider le panier
$("#basket").empty();
totalBasket = 0;
for(let i=0; i < basket.length; i++)
{
totalBasket = totalBasket + basket[i][4];
$("#basket").append("<tr><td>"+basket[i][1]+"</td>"
+"<td>"+basket[i][2]+"</td>"
+"<td>"+basket[i][3]+"€</td>"
+"<td>"+basket[i][4]+"€</td>"
+"<td><button data-id='"+i+"' class='btn_cancel_basket'>supprimer</button></td>"
+"</tr>");
}
// installer un event
$("#basket button.btn_cancel_basket").on("click",suppArticleBasket);
$("#totalBasket").text(totalBasket+" €");
}
function suppArticleBasket()
{
let index = $(this).data('id');
console.log(index);
basket.splice(index,1);
saveStorageBasket();
loadStorageBasket();
showBasket();
}
function showWishList()
{
for(let i=0; i < wishlist.length; i++)
{
$("#Wishlist").append("<tr><td>"+wishlist[i][1]+"</td>"
+"<td>"+wishlist[i][2]+"</td>"
+"</tr>");
}
}
function emptyBasket()
{
if(basket == null || basket == 0)
{
console.log("panier = true");
return true;
}else
{
console.log("panier = false");
return false;
}
}
function validateBasket()
{
if(emptyBasket() == false)
{
loadStorageBasket();
basket = JSON.stringify(basket); //js --> json
console.log($.get("index.php","action=appelAjax2&Basket="+basket+"&total="+totalBasket,resetBasket));
}
}
function resetBasket(reponse){
$("#confirmationcmd").html("<p>Commande validée.</p>");
$("#basket").empty();
basket.length = 0;
localStorage.clear();
loadStorageBasket();
showBasket();
totalBasket = 0;
calculeNbrArticle();
}
function resetBasket2(reponse){
$("#confirmationcmd").html("<p>Panier annulé.</p>");
$("#basket").empty();
basket.length = 0;
localStorage.clear();
loadStorageBasket();
showBasket();
totalBasket = 0;
calculeNbrArticle();
}
function resetWishlist(reponse){
$("#confirmationWishlist").html("<p>Wishlist remise à zéro.</p>");
$("#wishlist").empty();
wishlist.length = 0;
localStorage.clear();
loadStorageWishlist();
showWishList();
totalWishlist = 0;
calculeNbrWishlist();
}
function saveStorageWishlist(){
localStorage.setItem("myWishList", JSON.stringify(wishlist));
}
function loadStorageWishlist(){
wishlist = localStorage.getItem("myWishList");
if(wishlist == null)
{
wishlist =[];
}
else
{
wishlist = JSON.parse(wishlist);
}
}
function calculeNbrWishlist()
{
loadStorageWishlist();
nbrWishlist = wishlist.length;
$("#nbrWishlist").text("("+nbrWishlist+")");
}
function saveStorageBasket(){
localStorage.setItem("monPanier", JSON.stringify(basket));
}
function loadStorageBasket(){
basket = localStorage.getItem("monPanier");
if(basket == null)
{
basket =[];
}
else
{
basket = JSON.parse(basket);
}
}
function calculeNbrArticle()
{
loadStorageBasket();
nbrArticles = basket.length;
$("#nbrArticles").text("("+nbrArticles+")");
}
$(function()
{
calculeNbrArticle();
calculeNbrWishlist();
loadStorageBasket();
loadStorageWishlist();
showBasket();
showWishList();
$(".add_basket_btn").on('click',addBasket);
$(".btn_wishlist").on('click',addWishlist);
$("#validateButton").on('click',validateBasket);
$("#resetButton").on('click',resetBasket2);
$("#resetButtonWishlist").on('click',resetWishlist);
});

The basic idea:
push the new basket array if empty
check if the ID is already in the basket array
if so, update the quantity
if not, add the new basket
I have read the following learning resources about:
for loops (w3schools)
find (MDN)
filter (MDN)
According to what I have read in this post Array.find does not work because it finds only the first element. I used the suggested filter option.
The essential part with changes:
function updateQuantity(basket, newBasket, idArticle)
{
// filter: search for articleId in array of arrays
if (basket.filter(({ 1: n }) => n === idArticle)) {
for(i = 0; i < basket.length; i++) {
basket[i][1] += 1;
}
} else {
basket.push(newBasket)
}
}
function addBasket()
{
let quantity_cart = 1
let name_article_cart = "productName"
let idArticle = 1
let price_cart = 10
let total_price_cart = (quantity_cart * price_cart);
let newBasket = [idArticle,quantity_cart,name_article_cart,price_cart,total_price_cart];
if (basket.length === 0) {
basket.push(newBasket)
}
else
{
updateQuantity(basket, newBasket, idArticle)
}
console.log(basket)
}
My complete test code:
let basket = JSON.parse(localStorage.getItem('monPanier')) || [];
let totalBasket = 0;
let nbrArticles;
function updateQuantity(basket, newBasket, idArticle)
{
// filter: search for articleId in array of arrays
if (basket.filter(({ 1: n }) => n === idArticle)) {
for(i = 0; i < basket.length; i++) {
basket[i][1] += 1;
}
} else {
basket.push(newBasket)
}
}
function addBasket()
{
let quantity_cart = 1
let name_article_cart = "productName"
let idArticle = 1
let price_cart = 10
let total_price_cart = (quantity_cart * price_cart);
let newBasket = [idArticle,quantity_cart,name_article_cart,price_cart,total_price_cart];
if (basket.length === 0) {
basket.push(newBasket)
}
else
{
updateQuantity(basket, newBasket, idArticle)
}
console.log(basket)
}
function suppArticleBasket()
{
let index = 1
console.log(index);
basket.splice(index,1);
saveStorageBasket();
loadStorageBasket();
}
function emptyBasket()
{
if(basket == null || basket == 0)
{
return true;
} else
{
return false;
}
}
function saveStorageBasket(){
localStorage.setItem("monPanier", JSON.stringify(basket));
}
function loadStorageBasket(){
basket = localStorage.getItem("monPanier");
if(basket == null)
{
basket =[];
}
else
{
basket = JSON.parse(basket);
}
}
$(function()
{
loadStorageBasket();
$("#add_basket_btn").on('click',addBasket);
});
<button id="add_basket_btn">Add</button>

Related

Trying to toggle between read and unread

I am new to javascript and I am trying to have my button say read or unread when a user clicks on it I've tried adding my readBookfunction to the onclick but I get an error like this, any help would be appreciated
I want it to look like this below and have the button either be read or unread
script.js
class Book {
constructor(title, author, read) {
this.title = title;
this.author = author;
this.read = read;
addBookToLibrary(this);
}
}
let myLibrary = [];
const table = document.getElementById('libraryTable');
let hiddenForm = document.getElementById('hiddenForm')
//toggles the input form opacity and z-index
function showForm() {
hiddenForm.classList.toggle('active')
}
function clearInput() {
inputs = document.getElementsByTagName('input')
for (let i in inputs) {
inputs[i].value = ''
}
}
function createBook() {
new Book(document.getElementById('title').value,
document.getElementById('author').value,
document.getElementById('read').value);
}
const harrypotter = new Book('Harry Potter', 'JK Rowling', 'read')
const stripedpajamas = new Book('The Boy in the Striped pajamas', 'John Boyne', 'read')
const randomBook = new Book('The random book', 'random author', 'read')
function addBookToLibrary(book) {
myLibrary.push(book);
}
function readBook(Book) {
let position = 0;
for (i = 0; i < myLibrary.length; i++) {
if (Book.title == myLibrary[i].title) {
position = i;
}
}
if (myLibrary[position].read == 'read') {
myLibrary[position].read = "unread";
} else {
myLibrary[position].read = "read";
}
return myLibrary[position].read;
}
function displayBooks() {
table.textContent = '';
for (i = 0; i < myLibrary.length; i++) {
let newRow = table.insertRow(i);
newRow.insertCell(0).innerText = myLibrary[i].title;
newRow.insertCell(1).innerText = myLibrary[i].author;
newRow.insertCell(2).innerHTML = `<button onclick='${i}' class='tableButtons' >${myLibrary[i].read}</button>`
newRow.insertCell(2).innerHTML = `<button onclick='removeBook(${i})' class='tableButtons' >Delete</button>`
}
}
function removeBook(index) {
if (index > 1) {
myLibrary.splice(index, index - 1);
} else if (index == 1) {
myLibrary.splice(index, index);
} else if (index == 0) {
myLibrary.shift();
}
}
const displayButton = document.querySelector(".display");
displayButton.addEventListener('click', button => {
displayBooks();
});

How to repeat a function without effecting repeating the token

How do I modify the repeat loop function without it repeating the token variable in the function rowcount()?
function rowcount()
{
var token = getAccessToken();
var module = "sHistory";
var rows = 0;
var go = true;
var i = 1;
var data;
while (go) {
data = getRecordsByPage(i,200,token,module);
if (Number(data.info.count) < 200) {
go = false;
};
if ((i%10) == 0) {
go = false;
}
rows = Number(rows) + Number(data.info.count);
i++;
Logger.log(rows)
}
return rows
}
function repeatloop()
{
let counter = 0;
for(var i = 1; i <= 93; i++)
{
{
Utilities.sleep(10000);
Logger.log(i);
counter += rowcount();
Logger.log(counter);
}
}
return rowcount().rows;
}
What I am also trying to do is let the count continue because right now it goes in an increment of 2000, but I need it to continue like 200...400..600..800...1000...1200...1400...1600...1800...2000...2200. and it goes on until the loop stops.
You can make the token a global variable like this:
var token;
function rowcount()
{
var module = "sHistory";
var rows = 0;
var go = true;
var i = 1;
var data;
while (go) {
data = getRecordsByPage(i,200,token,module);
if (Number(data.info.count) < 200) {
go = false;
};
if ((i%10) == 0) {
go = false;
}
rows = Number(rows) + Number(data.info.count);
i++;
Logger.log(rows)
}
return rows
}
function repeatloop()
{
let counter = 0;
token = getAccessToken();
for(var i = 1; i <= 93; i++)
{
{
Utilities.sleep(10000);
Logger.log(i);
counter += rowcount();
Logger.log(counter);
}
}
return rowcount().rows;
}
Or did I understand you wrong?
I would pass the token as an optional parameter, insted to use GLOBAL variable:
function rowcount(_token = null)
{
let token;
if (_token) {token = _token;}
else {token = getAccessToken();}
var module = "sHistory";
var rows = 0;
var go = true;
var i = 1;
var data;
while (go) {
data = getRecordsByPage(i,200,token,module);
if (Number(data.info.count) < 200) {
go = false;
};
if ((i%10) == 0) {
go = false;
}
rows = Number(rows) + Number(data.info.count);
i++;
Logger.log(rows)
}
return rows
}
function repeatloop()
{
let token = getAccessToken();
let counter = 0;
for(var i = 1; i <= 93; i++)
{
{
Utilities.sleep(10000);
Logger.log(i);
counter += rowcount(token);
Logger.log(counter);
}
}
return rowcount(token).rows;
}

Why in this example using callback function in forEach method gives wrong output?

I am trying to use callback function with forEach method to print in the console the result of 3 prompts but instead I have 5 outputs.
const personalMovieDB = {
genres: [],
writeYourGenres: function () {
for (let i = 1; i <= 3; i++) {
let favoriteGenre = [];
while (favoriteGenre == null || favoriteGenre == "") {
favoriteGenre = prompt(`Your favorite movie genre under number ${i}`);
this.genres[i - 1] = favoriteGenre;
}
this.genres.forEach((item, i) => {
console.log(`Favorite genre ${i+1} - ${item}`);
});
}
}
}
Just remove printing functionality from a loop
const personalMovieDB = {
genres: [],
writeYourGenres: function() {
for (let i = 1; i <= 3; i++) {
let favoriteGenre = [];
while (favoriteGenre == null || favoriteGenre == "") {
favoriteGenre = prompt(`Your favorite movie genre under number ${i}`);
this.genres[i - 1] = favoriteGenre;
}
}
this.genres.forEach((item, i) => {
console.log(`Favorite genre ${i+1} - ${item}`);
});
}
}
personalMovieDB.writeYourGenres()

Why is array seemingly empty after the loop? [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 2 years ago.
function par(idF, idM) {
this.IDOvna = idM;
this.IDOvce = idF;
}
function breeding() {
let idOvce = [];
let brOvce = [];
let mesecOvce = [];
let godinaOvce = [];
let istorija1 = [];
let istorija2 = [];
let idOvna = [];
let brOvna = [];
let mesecOvna = [];
let godinaOvna = [];
let y = 0;
let o = 0;
let parovi = [];
let c = 0;
fetch("http://localhost/ovce/ovce.json")
.then(function(resp) {
return resp.json();
})
.then(function(data) {
console.log(data);
for (let i = 0; i < data.ovce.length; i++) {
idOvce[i] = data.ovce[i].id;
brOvce[i] = data.ovce[i].broj;
mesecOvce[i] = data.ovce[i].mesec;
godinaOvce[i] = data.ovce[i].godina;
istorija1[i] = data.ovce[i].istorija1;
istorija2[i] = data.ovce[i].istorija2;
}
});
fetch("http://localhost/ovce/ovnovi.json")
.then(function(resp1) {
return resp1.json();
})
.then(function(data1) {
console.log(data1);
for (let g = 0; g < data1.ovnovi.length; g++) {
idOvna[g] = data1.ovnovi[g].id;
brOvna[g] = data1.ovnovi[g].broj;
mesecOvna[g] = data1.ovnovi[g].mesec;
godinaOvna[g] = data1.ovnovi[g].godina;
}
});
while (o < idOvna.length) {
y = 0;
while (y < idOvce.length) {
if (istorija1[y] != 0) {
if ((istorija2[y] != idOvna[o]) && (istorija2[istorija1[y]] != idOvna[o])) {
parovi[c] = new par(idOvce[y], idOvna[o]);
c++;
}
} else {
parovi[c] = new par(idOvce[y], idOvna[o]);
c++;
}
y++;
}
o++;
}
console.log(parovi);
return parovi;
}
<html>
<head>
<title>Sheepify</title>
<script src="main.js"></script>
</head>
<body>
<button onclick="breeding()"> Breeding </button>
</body>
</html>
In javascript, i have a loop running and afterwards the pairs array which should be populated is empty.
function pair(idF, idM) {
this.IDOvna = idM;
this.IDOvce = idF;
}
function problem() {
let y = 0;
let o = 0;
let pairs = [];
let c = 0;
//id, id1, history1, history2 are arrays which are populated from the json files using fetch.
while (o < id.length) {
y = 0;
while (y < id1.length) {
if (history1[y] != 0) {
if ((history2[y] != id[o]) && (history2[history1[y]] != id[o])) {
pairs[c] = new pair(id1[y], id[o]);
c++;
}
} else {
pairs[c] = new pair(id1[y], id[o]);
c++;
}
y++;
}
o++;
}
console.log(pairs);
console.log(pairs.length);
}
When i run a debugger the array is populated and everything is fine, but when i execute the function on button click or through a console, it just returns an empty array. What could be causing this problem?
EDIT: I accidentally pasted the pair function inside the problem function, which isn't the case. I have moved it out now. And changed leght to length as suggested.
EDIT2: Here is the full code, sorry about the variable names, they are in Serbian.
The loop that processes the arrays is outside the fetch callback functions, so it doesn't wait for the arrays to be populated. See Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference.
You can make your function async and use await to wait for them.
Note also that the code that calls this will need to use await or .then() to get the returned parovi array. See How do I return the response from an asynchronous call?
async function breeding() {
let idOvce = [];
let brOvce = [];
let mesecOvce = [];
let godinaOvce = [];
let istorija1 = [];
let istorija2 = [];
let idOvna = [];
let brOvna = [];
let mesecOvna = [];
let godinaOvna = [];
let y = 0;
let o = 0;
let parovi = [];
let c = 0;
await fetch("http://localhost/ovce/ovce.json")
.then(function(resp) {
return resp.json();
})
.then(function(data) {
console.log(data);
for (let i = 0; i < data.ovce.length; i++) {
idOvce[i] = data.ovce[i].id;
brOvce[i] = data.ovce[i].broj;
mesecOvce[i] = data.ovce[i].mesec;
godinaOvce[i] = data.ovce[i].godina;
istorija1[i] = data.ovce[i].istorija1;
istorija2[i] = data.ovce[i].istorija2;
}
});
await fetch("http://localhost/ovce/ovnovi.json")
.then(function(resp1) {
return resp1.json();
})
.then(function(data1) {
console.log(data1);
for (let g = 0; g < data1.ovnovi.length; g++) {
idOvna[g] = data1.ovnovi[g].id;
brOvna[g] = data1.ovnovi[g].broj;
mesecOvna[g] = data1.ovnovi[g].mesec;
godinaOvna[g] = data1.ovnovi[g].godina;
}
});
while (o < idOvna.length) {
y = 0;
while (y < idOvce.length) {
if (istorija1[y] != 0) {
if ((istorija2[y] != idOvna[o]) && (istorija2[istorija1[y]] != idOvna[o])) {
parovi[c] = new par(idOvce[y], idOvna[o]);
c++;
}
} else {
parovi[c] = new par(idOvce[y], idOvna[o]);
c++;
}
y++;
}
o++;
}
console.log(parovi);
return parovi;
}
function par(idF, idM) {
this.IDOvna = idM;
this.IDOvce = idF;
}
<html>
<head>
<title>Sheepify</title>
<script src="main.js"></script>
</head>
<body>
<button onclick="breeding()"> Breeding </button>
</body>
</html>
how are you using this problem function within the fetch?
If you are using int outside the fetch its totaly normal, your arrays will be empty.
Edit:
As you have post the fetch method, you need to put all your while loop un the last then, when you are populating the data, because fetch is async =/
Since you have two fetch, and both are populating the array's you need to do the second in the last then of the first fetch. And finaly you can do your while loop in last then of your second fetch.
It may be more clearner using async await method.
function par(idF, idM) {
this.IDOvna = idM;
this.IDOvce = idF;
}
function breeding() {
let idOvce = [];
let brOvce = [];
let mesecOvce = [];
let godinaOvce = [];
let istorija1 = [];
let istorija2 = [];
let idOvna = [];
let brOvna = [];
let mesecOvna = [];
let godinaOvna = [];
let y = 0;
let o = 0;
let parovi = [];
let c = 0;
fetch("http://localhost/ovce/ovce.json")
.then(function(resp) {
return resp.json();
})
.then(function(data) {
console.log(data);
for (let i = 0; i < data.ovce.length; i++) {
idOvce[i] = data.ovce[i].id;
brOvce[i] = data.ovce[i].broj;
mesecOvce[i] = data.ovce[i].mesec;
godinaOvce[i] = data.ovce[i].godina;
istorija1[i] = data.ovce[i].istorija1;
istorija2[i] = data.ovce[i].istorija2;
}
fetch("http://localhost/ovce/ovnovi.json")
.then(function(resp1) {
return resp1.json();
})
.then(function(data1) {
console.log(data1);
for (let g = 0; g < data1.ovnovi.length; g++) {
idOvna[g] = data1.ovnovi[g].id;
brOvna[g] = data1.ovnovi[g].broj;
mesecOvna[g] = data1.ovnovi[g].mesec;
godinaOvna[g] = data1.ovnovi[g].godina;
while (o < idOvna.length) {
y = 0;
while (y < idOvce.length) {
if (istorija1[y] != 0) {
if ((istorija2[y] != idOvna[o]) && (istorija2[istorija1[y]] != idOvna[o])) {
parovi[c] = new par(idOvce[y], idOvna[o]);
c++;
}
} else {
parovi[c] = new par(idOvce[y], idOvna[o]);
c++;
}
y++;
}
o++;
}
console.log(parovi);
return parovi;
}
});
});
}

Problems with searching arrays

I wrote my code to search string for keywords and extracting needed data, but I have problems when I'm trying to search with keywords in arrays named: sort, title and artist. When I'm doing it I get an error about potential infinite loop.
var type = ['track','tracks','song','songs','album','albums'];
var artist = ['created by', 'made by'];
var genre = ['genre'];
var limit = ['set limit'];
var title = ['title','name'];
var sort = ['sort by', 'classificate by', 'separate by'];
var sortBy = ['popularity'];
// function changeWordsToNumbers(words) {
// if (msg.numbers[words])
// return msg.numbers[words];
// }
function searchForIndex(instruction, keywords) {
for (i = 0; i < keywords.length; i++) {
let search = instruction.search(keywords[i]);
if (search)
return search;
}
return false;
}
function getSearchResult(wanted) {
var searchResult = {
artist : searchForIndex(wanted, artist),
genre : searchForIndex(wanted, genre),
limit : searchForIndex(wanted, limit),
type : searchForIndex(wanted, type),
title : searchForIndex(wanted, title),
sort : searchForIndex(wanted, sort),
sortBy : searchForIndex(wanted, sortBy)
};
return searchResult;
}
function removeJunkKeyword(searchResult,instruction) {
for(var property in searchResult) {
if(searchResult.hasOwnProperty(property)) {
if(searchResult[property] != - 1) {
instruction = instruction.slice(0, searchResult[property] - 1);
}
}
}
return instruction;
}
function checkExist(searchResult) {
for(var property in searchResult) {
if(searchResult.hasOwnProperty(property)) {
if(searchResult[property] != -1)
return false;
}
}
return true;
}
function findAndCleanQuery(instruction, keywords) {
var exist = instruction.search(keywords);
var result = instruction.slice(exist + keywords.length + 1, instruction.length);
var searchResult = getSearchResult(result);
if (exist != -1) {
if (checkExist(searchResult)) {
return result;
} else {
result = removeJunkKeyword(searchResult,result);
return result;
}
}
return false;
}
function searchFor(instruction, keywords) {
for (i = 0; i < keywords.length; i++) {
let result = findAndCleanQuery(instruction,keywords[i]);
if (result)
return result;
}
return false;
}
function searchForType(instruction) {
for (i = 0; i < type.length; i++) {
let search = instruction.search(type[i])
if(search)
return type[i];
}
return false;
}
function searchForKeywords(instruction) {
msg.artist = searchFor(instruction, artist);
msg.type = searchForType(instruction, type);
msg.genre = searchFor(instruction, genre);
msg.limit = searchFor(instruction, limit);
msg.title = searchFor(instruction, title);
msg.sort = searchFor(instruction, sortreg);
}
var msg = {}
msg.instruction = 'Search for me';
searchForKeywords(msg.instruction);
console.log(msg.artist);
console.log(msg.type);
console.log(msg.genre);
console.log(msg.limit);
console.log(msg.title);
console.log(msg.sort);
Link for code: https://repl.it/J4Mc/9
PS. The object msg is used by node-red to communicate between nodes.
The issue is that you're doing this on several of your loops:
for (i = 0; i < keywords.length; i++) {
...where you should be doing this instead:
for (let i = 0; i < keywords.length; i++) {
Without using let, the variable i is effectively global. Each time you went into a new loop it got reset to 0, so it was never able to increase, which created the infinite loop.
As a side note, you'll also notice sortreg is undefined when it's used on line 98.

Categories