How to avoid getting duplicated elements on localstorage array - javascript

i have the following code that generates a new element on an array in my localstorage each time i click on a button
let addCartItemButtons = document.getElementsByClassName('product-description-add')
for (let i = 0; i < addCartItemButtons.length; i++){
let button = addCartItemButtons[i]
button.addEventListener('click', function(event){
let buttonClicked = event.target
let getTitle = buttonClicked.parentElement.parentElement.parentElement.querySelector('.product-title').innerText
let getImage = buttonClicked.parentElement.parentElement.parentElement.querySelector('.product-header img').src
let getColor = buttonClicked.parentElement.parentElement.querySelector('.product-description-text li span').innerText
let getSize = buttonClicked.parentElement.parentElement.querySelector('.product-description-text li select').value
let getPrice = buttonClicked.parentElement.parentElement.querySelector('.product-description-price').innerText
let getSpan = buttonClicked.parentElement.parentElement.querySelector('li span').getAttribute('id')
let oldItems = JSON.parse(localStorage.getItem('newProduct')) || [];
let newItem = {
'id': i+1,
'title': getTitle,
'image': getImage,
'color': getColor,
'size': getSize,
'price': getPrice,
'spanid': getSpan,
};
let data = JSON.parse(localStorage.getItem('newProduct'))
if(localStorage.getItem('newProduct') == null) {
oldItems.push(newItem);
localStorage.setItem('newProduct', JSON.stringify(oldItems));
} else {
if(data.indexOf(newItem) == -1){
oldItems.push(newItem);
localStorage.setItem('newProduct', JSON.stringify(oldItems));
}else{
alert('element already added')
}
}
})
}
My problem is that I've tried to create a validation to check if the element has already been added to the local storage, so in that case there should appear the alert, but it's not working at all and I'm still being able to add an element to my localstorage after I added it for the first time. I can't get of how to resolve this, any ideas? :)

Problems are arising because objects do not compare as equal just because they have the same property values.
let oldItems = JSON.parse(localStorage.getItem('newProduct')) || [];
creates oldItems as an empty array or an Array of newly created objects with property values representing previous items clicked and saved.
let data = JSON.parse(localStorage.getItem('newProduct'))
will also create an array of new objects for previous buttons clicked, if there were any, but won't contain the same objects as oldItems because JSON.parse creates new objects each time it is called.
Defining newItem also creates a new object which will not be the same object as any of the entries in oldItems or data.
To solve the problem you could add unique product codes to all items, so you can search previous data for a match based on product code alone, or write a comparison routine to check all the properties that need differentiating (such as color).
Personally I would try to get a product-id added into page data, search for it among previous items, and if product-ids match, then then the item has been been clicked before (but the customer could be ordering a different color).
Be wary of using the button loop counter as an id value, or even the image source string - it's easy to imagine ways they could go wrong or be compromised by page changes outside your control.

So thanks for the help I've received from #traktor, I was able to come up with a solution to this problem. I've added a data-prodid to each product and then pass it as 'id' to localstorage. Then I check if there's any element in my array that contains the same ID i'm clicking into and if there's any result, then an alert gets executed. Otherwise, the element gets saved.
let addCartItemButtons = document.getElementsByClassName('product-description-add')
for (let i = 0; i < addCartItemButtons.length; i++){
let button = addCartItemButtons[i]
button.addEventListener('click', function(event){
let buttonClicked = event.target
let getProdId = buttonClicked.parentElement.parentElement.parentElement.getAttribute('data-prodid')
let getTitle = buttonClicked.parentElement.parentElement.parentElement.querySelector('.product-title').innerText
let getImage = buttonClicked.parentElement.parentElement.parentElement.querySelector('.product-header img').src
let getColor = buttonClicked.parentElement.parentElement.querySelector('.product-description-text li span').innerText
let getSize = buttonClicked.parentElement.parentElement.querySelector('.product-description-text li select').value
let getPrice = buttonClicked.parentElement.parentElement.querySelector('.product-description-price').innerText
let getSpan = buttonClicked.parentElement.parentElement.querySelector('li span').getAttribute('id')
let oldItems = JSON.parse(localStorage.getItem('newProduct')) || [];
let newItem = {
'id': getProdId,
'title': getTitle,
'image': getImage,
'color': getColor,
'size': getSize,
'price': getPrice,
'spanid': getSpan,
};
if(localStorage.getItem('newProduct') == null) {
oldItems.push(newItem);
localStorage.setItem('newProduct', JSON.stringify(oldItems));
} else {
let data = JSON.parse(localStorage.getItem('newProduct'))
let idCheck = data.filter(x => x.id === newItem.id).map(x => x.foo);
let idCheckResults = idCheck.length
if(idCheckResults > 0){
alert('element already added')
}else{
oldItems.push(newItem);
localStorage.setItem('newProduct', JSON.stringify(oldItems));
}
}
let windowCartProducts = JSON.parse(window.localStorage.getItem("newProduct"));
let productsInCart = document.getElementById('cartProducts')
let productsAdded = 0
for(let i = 0; i < windowCartProducts.length; i++){
productsAdded = windowCartProducts.length
}
productsInCart.innerHTML = productsAdded + `<i class="fas fa-shopping-cart"></i>`
})
}

Related

Error in my task 4, it seems that .checked and .value doesn't seem to work as intended

Link to Scrimba to check on code : https://scrimba.com/scrim/czvrQJcM
Essentially what should happen is that when the details are added and the button is clicked, the data first gets saved into the object, 'student' and pushed into the array. Then the array is run and the students names are displayed on the page.
I just solve your problem. Look:
At your enrolStudent() function you set the following line:
studentList = studentList.push(student);
So, you should change it to:
studentList.push(student);
This is because the push() method returns the length of the array. So, you don't need to attribute the operation result to the array. The method already updated its own value.
Task4 after the change:
function enrolStudent()
{
let firstnameRef = document.getElementById("fname");
let lastnameRef = document.getElementById("lname");
let studentIdRef = document.getElementById("studentid");
let dateRef = document.getElementById("date");
let courseRef = document.getElementById("course");
let genderRef = document.getElementsByName("gender");
for (let i=0; i < genderRef.length; i++)
{
if (genderRef[i].checked)
{
var genderSelection = genderRef[i];
}
}
let student = new Object();
student.firstName = firstnameRef.value;
student.lastName = lastnameRef.value;
student.id = studentIdRef.value;
student.course = studentIdRef.value;
student.gender = genderSelection.value;
student.date = dateRef.value;
studentList.push(student);
var val = studentList.push(student);
studentEnrolSummaryRef.innerHTML = displayStudents(studentList);
console.log(val);
}
```

Changing the data of the repeater in wix

I'm trying to manipulate the repeater list in Wix. When the user selects the quantity of equipment, that number of forms show up. I got the hang of it when I see it in the console log but when I try to display it on the web, it gives me an error. I've tried reassigning $w("#repeater1").data to newArr(the new data).
Here's my code
$w("#repeater1").hide();
let itemOptions = $w("#quoteDropdown").options
$w("#quoteDropdown").onChange((event) => {
$w("#repeater1").show();
const arrOfValues = []
let newArr = []
let repeaterData = $w("#repeater1").data;
let quantity = Number(event.target.value);
let iterator = repeaterData.values();
for(const value of iterator) {
arrOfValues.push(value);
}
for(let i = 0 ; i < itemOptions.length; i++) {
newArr = repeaterData.slice(0, quantity);
}
if(quantity > newArr.length) {
let newItems = arrOfValues.filter(arr => {
newArr.forEach(na => arr !== na)
})
newArr.push(newItems)
}
console.log("newArr");
console.log(newArr);
// $w("#repeater1").data is the original data from the repeater
// newArr is the altered data from the repeater based on how it appears based on the users' interaction.
// I've tried each one of these
// $w("#repeater1").data = newArr;
// return newArr;
}); // end onChange
If you're trying to assign the array as the data for a repeater, you need to follow some rules. First, it needs to be an array of objects. Second, each object needs to have an _id property.

Having Trouble Accessing the Value of a Score stored in Local Storage

I'm having issues when trying to access the value of a score that is stored in the localStorage from a variable that is equal to how many questions the user gets right. I thought it would be exactly the same as setting the value but most likely I've done something wrong, and I lack the experience to figure it out..
I Want to display the User's score on the screen's scoreboard where the complete button is. I easily set the score into the localStorage with the setItem(users, score) line, but it seems getItem(score) doesn't work when I want to set displayUser.textContent = getItem(score).
I've tried a lot of different ways, and I always get null. I also noticed every time I submit a new entry to the scoreboard, the key's name keeps the last entries name and stores it on the end.
I'd love to fix this myself, but after making no progress or any leads for 3 hours, I think I might ask for some help. I reused and changed a lot of this code from a class activity in my boot camp so the complete button is just there to remove entries while in development.
Here's all of the relevant JavaScript hopefully
//Variables to Shorten text
var startButton = document.getElementById('startbtn')
var nextButton = document.getElementById('nextbtn')
var finishEarlyButton = document.getElementById('finishEarlyBtn')
var introSection = document.getElementById('intro')
var questionSection = document.getElementById('Question-Section')
var questionElement = document.getElementById('question')
var answerButtons = document.getElementById('Answer-Section')
var scoreboard = document.getElementById('Score-Container')
var userScore = document.getElementById('Score')
var seeScoreBtn = document.getElementById('seeScore')
var restartBtn = document.getElementById('restart')
var finishbtn = document.getElementById('finishbtn')
var userAnswer = ""
var shuffledQuestions, currentQuestionIndex
var score = 0
var userName = document.getElementById('scoreboard-input')
var leaderboard = document.getElementById('leaderboard')
var leaderboardUsers = document.getElementById('leaderboardUsers')
var users = [];
init();
function init() {
var storedUsers = JSON.parse(localStorage.getItem("Users"))
if (storedUsers !== null) {
users = storedUsers;
renderUsers();
}
}
function renderUsers() {
leaderboardUsers.innerHTML = "";
for (var i = 0; i < users.length; i++) {
var user = users[i];
var li = document.createElement("li");
li.textContent = user;
li.setAttribute("data-index", i);
var button = document.createElement("button");
button.textContent = "Complete";
var displayUser = document.createElement("button");
displayUser.textContent = (localStorage.getItem(score));
//displayUser.textContent = "test";
console.log(localStorage.getItem(users.value))
li.appendChild(displayUser);
li.appendChild(button);
leaderboardUsers.appendChild(li);
}
}
function storeUsers() {
//localStorage.setItem("users", JSON.stringify(users));
//localStorage.setItem(JSON.stringify(users), JSON.stringify(score));
localStorage.setItem(users, score);
}
leaderboard.addEventListener("submit", function() {
event.preventDefault();
var userText = userName.value.trim();
var userCorrectAnswers = score.value;
if (userText === "") {
return
}
//users.push(userCorrectAnswers);
users.push(userText);
userName.value = "";
storeUsers()
renderUsers()
console.log
})
leaderboardUsers.addEventListener("click", function(event) {
var element = event.target;
if (element.matches("button") === true) {
var index = element.parentElement.getAttribute("data-index");
users.splice(index, 1);
storeUsers();
renderUsers();
}
})
Let me know if the html or rest of JS is needed!
Well just by looking at the code we can see that you're accessing it via
var storedUsers = JSON.parse(localStorage.getItem("Users"))
and storing it via
localStorage.setItem(users, score);
With the way you're accessing it, you would set it via
localStorage.setItem("Users", JSON.stringify(users));
It is case-sensitive, which is probably why your attempt of using the key users didn't work in your first comment under your storeUsers function.
This is a lot of code to sift through but setting and getting items requires string key-names and stringified values:
localStorage.setItem('users', JSON.stringify(score))
JSON.parse(localStorage.getItem('users'))
This way you should have the same data before and after setting to localStorage.
You are not using localStorage setItem correctly.
localStorage.setItem(users, score);
Both arguments to setItem() must be strings, with the first argument a key, and the second argument the value to store. Your first argument is an array (the data type of your second argument is unclear).
Typical value of a setItem first argument: 'usersScores'.
localStorage.setItem('usersScores', JSON.stringify(score));
Note the use of JSON.stringify() to convert score to a string, because localStorage only stores data in string form.
You are also not using getItem correctly:
localStorage.getItem(score)
getItem must be called with the key used in setItem:
localStorage.getItem('userScores')
And since score was saved as a string, you need to convert it back when you read it from localStorage:
score = JSON.parse(localStorage.getItem('userScores'))
How to use localStorage is explained clearly in MDN web docs Using the Web Storage API.

How to select specified data like id in a for loop to use those data in different page

I want to get and store id from idArray to use each id indvidual
I tried to store in session storage but it return the last element
success: function (data) {
const myText = "";
const addressArray = [];
const titleArray = [];
const typeArray = [];
const idArray = [];
data.map((user) => {
addressArray.push(user.address);
titleArray.push(user.title);
typeArray.push(user.jtype);
idArray.push(user.id);
});
container.innerHTML = "";
for (let i = 0; i <= 3; i++) {
let clone = row.cloneNode(true);
container.appendChild(clone);
container.firstChild.innerHTML = "";
jobtitle.innerHTML = data[i].title;
jbtype.innerHTML= typeArray[i];
jbaddress.innerHTML= addressArray[i];
sessionStorage.setItem('jobid',idArray[i]);
}
}
The issue I can see is , since the key is always same , it is overriding the value of the same key.
You can instead do something like
sessionStorage.setItem("jobid-"+i,idArray[i]);
This should solve the problem for sure.
It returns the last value because you are using the same key to store each value. Try using a different key for each or alternately, create an array of ids using map function and store the array in session with the key 'jobid'.
You can serialize and store it in session as follows:
sessionStorage.setItem('jobid', JSON.stringify(idArray));
To read the same back out you can use code like
JSON.parse(sessionStorage.getItem('jobid'));

Problem with Looping through over a newly created list element by js

I am building a Todo-List Project and i am stuck at looping through my newly created list items.
This is what i am doing:
Created an array.
Made li items for array's each element through looping so that array appears in a list manner.
And then looping through newly created li section to addEventListener on each of li's ( But this one is not working).
var arrList = ["play","learn","walk"];
var list = document.querySelectorAll("li");
var done = false;
//printing array in list manner
for(let i = 0; i < arrList.length; i++){
let el = document.createElement("li")
el.textContent = arrList[i];
document.querySelector("ul").appendChild(el);
}
//looping through each li's to apply if else statement
for(let i = 0; i < list.length; i++){
list[i].addEventListener("click",function(){
if(!done){
this.style.textDecoration = "line-through";
done = true;
}else{
this.style.textDecoration = "none";
done = false;
}
})
}
You're code is mostly correct, however there are a few issues that need to be addressed. First, consider replacing your for loop with iteration based on forEach() as shown below. Using forEach() in this way allows you to leverage "closure" which in this case will greatly simplify your code. For instance, you can use the closure feature to store the done state of each item in your list, rather than storing that state explicitly in an array.
The other issue I noticed was var list = document.querySelectorAll("li"); queries the document for li elements before any are added to your document - later in your script it seems you're iterating that empty query result and expecting it to contain the added li elements.
Here's a working snippet - hope this helps!
var arrList = ["play", "learn", "walk"];
// Iterate the list via forEach
arrList.forEach(function(arrItem) {
// We're now in a new "closure" for this list item
// so we can define some state like "done" that will
// be used exclusively for this list item
var done = false;
// Create li element for this list item as before
var el = document.createElement("li")
el.textContent = arrItem;
// Configure click event
el.addEventListener("click", function() {
// Notice we're able to use the done variable
// in this closure for this list item? The key
// thing to understand is that each list item
// will have it's own unique "done" variable
if (!done) {
el.style.textDecoration = "line-through";
done = true;
} else {
el.style.textDecoration = "none";
done = false;
}
})
document.querySelector("ul").appendChild(el);
});
<ul></ul>
It seems like you only have one done variable that is shared for every item on the todo list. Therefore if you click one of the items all of the items will be crossed out. You will need a boolean variable for every item in your to do list.
Add this line just above the second for loop and remove from the top.
var list = document.querySelectorAll("li");
You are assigning list the values even before they are created.
from the source code I see that the list li item is initialized before new li item been created,
it will cause the list li item not contains the new one,
due to that addEventListener will not working for the new item.
to fix this, just need move init list li item code after creation part :
var arrList = ["play","learn","walk"];
var done = false;
//printing array in list manner
for(let i = 0; i < arrList.length; i++){
let el = document.createElement("li")
el.textContent = arrList[i];
document.querySelector("ul").appendChild(el);
}
var list = document.querySelectorAll("li");
//looping through each li's to apply if else statement
for(let i = 0; i < list.length; i++){
list[i].addEventListener("click",function(){
if(!done){
this.style.textDecoration = "line-through";
done = true;
}else{
this.style.textDecoration = "none";
done = false;
}
})
}
Please, be simple...
var
arrList = ["play","learn","walk"],
UL_arrList = document.querySelector("ul")
;
arrList.forEach (arrItem => {
let el = document.createElement("li");
el.textContent = arrItem;
UL_arrList.appendChild(el);
el.onclick = function(e){
let deco = this.style.textDecoration || 'none';
this.style.textDecoration = (deco==='none') ? 'line-through': 'none';
}
});
<ul></ul>

Categories

Resources