Changing the data of the repeater in wix - javascript

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.

Related

How to avoid getting duplicated elements on localstorage array

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>`
})
}

compare the current and previous version of the same array for change in value in javascript

I have a following data array :
[{"name":"joseph","time":"0","status":"Idle"}] //there are multiple objects inside the array
This array of objects is generated every second by a node js service. I want to compare the newly created array with the previously created array to check for the change of the status.
eg
case 1
newly created
[{"name":"joseph","time":"0","status":"Idle"}]
previously created
[{"name":"joseph","time":"0","status":"Idle"}]
comparing the status of new and previous object : No change in status
case 2
newly created
[{"name":"joseph","time":"0","status":"Calling"}]
previously created
[{"name":"joseph","time":"0","status":"Idle"}]
comparing the status of new and previous object : status has changed
I hope you get the point.
If the status has changed then assign the current time to the time key;
I'm not able to figure out how to save the previous array and compare it with the newly created array.
What I have done so far:
newarray = [{"name":"joseph","time":"0","status":"Calling"}];
previousarray = newarray;
for(i=0;i<=newarray.length;i++){
for(j=0;j<previousarray.length;j++){
if(previousarray[j].status != newarray[i].status){
newarray[i].time = moment().format('H:mm:ss');
}
}
}
but this doesn't work. I get error like :
TypeError: Cannot read property 'status' of undefined
How do I do it?
First your previousArray is a reference to the newArray using =
Use the spread operator syntax instead:
const previousArray = [...newArray];
Then in the first loop you have <= instead of <
const newarray = [{"name":"joseph","time":"0","status":"Calling"}];
const previousarray = [...newarray];
for(let i = 0; i < newarray.length; i++) {
for(let j = 0; j < previousarray.length; j++) {
if(previousarray[j].status != newarray[i].status) {
newarray[i].time = moment().format('H:mm:ss');
}
}
}
can do in the below possible way. assuming newly_created & previously_created
newly_created = [{"name":"joseph","time":"0","status":"Calling"}, {"name":"joseph - 2","time":"0","status":"Idle"}, {"name":"joseph - 3","time":"0","status":"Calling"}];
previously_created = [{"name":"joseph","time":"0","status":"Idle"}, {"name":"joseph - 2","time":"0","status":"Calling"}, {"name":"joseph - 3","time":"0","status":"Calling"}];
newly_created.forEach(function(newArrObj, index){
if(newArrObj.status !== previously_created[index].status){
// newArrObj.time = moment().format('H:mm:ss');
newArrObj.time = new Date().toTimeString().split(' ')[0];
}
});
console.log('New Array : ', newly_created);
I think you want to do something like this:
newarray = {"name":"joseph","time":"0","status":"Calling"};
previousarray = newarray;
if(previousarray['status'] !== newarray['status']){
newarray['time'] = "date-time";
}

Problem when creating a dynamic table in JS. The numbers are presented separately

I'm having trouble creating a dynamic table in JavaScript. The numbers are presented separately, despite being presented as a sum in the console.
I create a program that counts reports per category fetched from a specific website that I do not mention here. Thank you in advance!
fetch('The websites url')
.then(function (response) {
return response.json()
})
.then(function (result) {
var reports = result.requests[0].request
let reportsPerCategory = {}
for (let i = 0; i < reports.length; i++) {
var category = result.requests[0].request[i].service_code
if(reportsPerCategory[category] === undefined){
reportsPerCategory[category] = 1
var tr3 = document.createElement("tr")
document.getElementById("table2").appendChild(tr3)
tr3.textContent = category
var td8 = document.createElement("td")
tr3.appendChild(td8)
}else {
td8.textContent = reportsPerCategory[category]++
//The result in the table cells isn't a sum of eacy category repeat
}
}
//Logs each category with the sum of repeats correctly in an array
console.log(Object.entries(reportsPerCategory))
})
.catch(function(error) {
console.error(error)
})
If reportsPerCategory[category] already exists, you increase the count and set its result to td8. That however is not the element containing the count of that category, but the element containing the count of the previous iteration. To resolve that you have to also create a map of elements:
var td8s = {};
then when you create a new td8 store it:
td8s[category] = td8;
and in the else { branch retrieve it with
td8s[category].textContent = /*...*/
or you just generate the table after counting.

Function output replaces first two rows of my main JSON string

I have a JSON query and I am using console.log to present it:
var json_data = {"headers":["Month","Value","Number"],"rows":[["2018-10-01 00:00:00.0","one",209],["2018-09-01 00:00:00.0","one",274],["2018-09-01 00:00:00.0","five",183],["2018-10-01 00:00:00.0","five",164],["2018-09-01 00:00:00.0","four",214],["2018-10-01 00:00:00.0","four",192],["2018-09-01 00:00:00.0","three",128],["2018-10-01 00:00:00.0","three",125],["2018-09-01 00:00:00.0","two",199],["2018-10-01 00:00:00.0","two",169],["2018-09-01 00:00:00.0","seven",10541],["2018-10-01 00:00:00.0","seven",6139],["2018-10-01 00:00:00.0","six",169],["2018-09-01 00:00:00.0","six",233]]};
document.getElementById("original").innerHTML = json_data.rows;
<div style="background:yellow; "id="original"></div>
<div style="background:red;" id="output"></div>
And for the value "one" I have two numbers (209 and 274).
I am then using a function to groupby which works fine (output). My problem is that when I use the console.log for the initial json_data query, the first two rows are different. It seems that my function replaced the first two rows with the rows of the output (red). The function is given here:
function initialGroupBy(rows) {
const
rowMap = new Map(),
result = [],
dataTemp = [];
// Iterate over the rows.
rows.forEach(row => {
const
// Create a key, it is the first elements joined together.
key = row.slice(0,1).join();
// Check if the Map has the generated key...
if (rowMap.has(key)) {
// The map has the key, we need to add up the values
const
// Get the value for the current key.
storedRow = rowMap.get(key);
// Add the value of the current row to the row in the map.
storedRow[2] += row[2];
} else {
// The key doens't exist yet, add the row to the map.
rowMap.set(key, row);
}
});
// Iterate over all the entries in the map and push each value with the
// summed up value into the array.
rowMap.forEach(value => {
result.push(value);
});
for (i = 0; i < result.length; i++)
{
var object2 = {"date": result[i][0].slice(0,7), "num": result[i][2]};
dataTemp.push(object2);
}
return dataTemp;
}
A full snippet can be found here (Compare the first two rows of the yellow box from the two snippets):
var json_data = {"headers":["Month","Value","Number"],"rows":[["2018-10-01 00:00:00.0","one",209],["2018-09-01 00:00:00.0","one",274],["2018-09-01 00:00:00.0","five",183],["2018-10-01 00:00:00.0","five",164],["2018-09-01 00:00:00.0","four",214],["2018-10-01 00:00:00.0","four",192],["2018-09-01 00:00:00.0","three",128],["2018-10-01 00:00:00.0","three",125],["2018-09-01 00:00:00.0","two",199],["2018-10-01 00:00:00.0","two",169],["2018-09-01 00:00:00.0","seven",10541],["2018-10-01 00:00:00.0","seven",6139],["2018-10-01 00:00:00.0","six",169],["2018-09-01 00:00:00.0","six",233]]};
function initialGroupBy(rows) {
const
rowMap = new Map(),
result = [],
dataTemp = [];
// Iterate over the rows.
rows.forEach(row => {
const
// Create a key, it is the first elements joined together.
key = row.slice(0,1).join();
// Check if the Map has the generated key...
if (rowMap.has(key)) {
// The map has the key, we need to add up the values
const
// Get the value for the current key.
storedRow = rowMap.get(key);
// Add the value of the current row to the row in the map.
storedRow[2] += row[2];
} else {
// The key doens't exist yet, add the row to the map.
rowMap.set(key, row);
}
});
// Iterate over all the entries in the map and push each value with the
// summed up value into the array.
rowMap.forEach(value => {
result.push(value);
});
for (i = 0; i < result.length; i++)
{
var object2 = {"date": result[i][0].slice(0,7), "num": result[i][2]};
dataTemp.push(object2);
}
return dataTemp;
}
const damn = initialGroupBy(json_data.rows);
document.getElementById("original").innerHTML = json_data.rows;
document.getElementById("output").innerHTML =JSON.stringify(damn);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div style="background:yellow; "id="original"></div>
<br><br>
<div style="background:red;" id="output"></div>
I have tried changing the var to const in many cases. Am I missing a fundamental JavaScript case here?
As your value is an Array object, when you save it in your temporary Map, you're actually using a reference to your original data structure row.
So in the first forEach loop, where you sum the values you're actually changing the original array entry.
The solution is pretty simple, just clone the array:
rowMap.set(key, row.slice());
Another possibility is to use a different array to save the totals.
Here is your code with the fix.
var json_data = {"headers":["Month","Value","Number"],"rows":[["2018-10-01 00:00:00.0","one",209],["2018-09-01 00:00:00.0","one",274],["2018-09-01 00:00:00.0","five",183],["2018-10-01 00:00:00.0","five",164],["2018-09-01 00:00:00.0","four",214],["2018-10-01 00:00:00.0","four",192],["2018-09-01 00:00:00.0","three",128],["2018-10-01 00:00:00.0","three",125],["2018-09-01 00:00:00.0","two",199],["2018-10-01 00:00:00.0","two",169],["2018-09-01 00:00:00.0","seven",10541],["2018-10-01 00:00:00.0","seven",6139],["2018-10-01 00:00:00.0","six",169],["2018-09-01 00:00:00.0","six",233]]};
function initialGroupBy(rows) {
const
rowMap = new Map(),
result = [],
dataTemp = [];
// Iterate over the rows.
rows.forEach(row => {
const
// Create a key, it is the first elements joined together.
key = row.slice(0,1).join();
// Check if the Map has the generated key...
if (rowMap.has(key)) {
// The map has the key, we need to add up the values
const
// Get the value for the current key.
storedRow = rowMap.get(key);
// Add the value of the current row to the row in the map.
storedRow[2] += row[2];
} else {
// The key doens't exist yet, add the row to the map.
rowMap.set(key, row.slice());
}
});
// Iterate over all the entries in the map and push each value with the
// summed up value into the array.
rowMap.forEach(value => {
result.push(value);
});
for (i = 0; i < result.length; i++)
{
var object2 = {"date": result[i][0].slice(0,7), "num": result[i][2]};
dataTemp.push(object2);
}
return dataTemp;
}
const damn = initialGroupBy(json_data.rows);
document.getElementById("original").innerHTML = json_data.rows;
document.getElementById("output").innerHTML =JSON.stringify(damn);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div style="background:yellow; "id="original"></div>
<div style="background:red;" id="output"></div>
A) The const declaration creates a read-only reference to a value. It does not mean the value it holds is immutable -> Link
B) Your problem is that you are actually editing the original object in the initialGroupBy function. Maybe this answer will be helpful.
A different logic applies here and the result is handy:
var json_data = {"headers":["Month","Value","Number"],"rows":[["2018-10-01 00:00:00.0","one",209],["2018-09-01 00:00:00.0","one",274],["2018-09-01 00:00:00.0","five",183],["2018-10-01 00:00:00.0","five",164],["2018-09-01 00:00:00.0","four",214],["2018-10-01 00:00:00.0","four",192],["2018-09-01 00:00:00.0","three",128],["2018-10-01 00:00:00.0","three",125],["2018-09-01 00:00:00.0","two",199],["2018-10-01 00:00:00.0","two",169],["2018-09-01 00:00:00.0","seven",10541],["2018-10-01 00:00:00.0","seven",6139],["2018-10-01 00:00:00.0","six",169],["2018-09-01 00:00:00.0","six",233]]};
function groupBy(accumulator, item) {
const [date,extra,value] = item;
const key = date.slice(0,7);
if(!accumulator[key]){
accumulator[key] = 0
}
accumulator[key] += value;
return accumulator;
}
var damn = json_data.rows.reduce(groupBy,{});
damn = Object.keys(damn).map(function(key){
return {date: key, Value: "Total", num: damn[key]};
})
document.getElementById("original").innerHTML = json_data.rows;
document.getElementById("output").innerHTML =JSON.stringify(damn);
<div style="background:yellow; "id="original"></div>
<div style="background:red;" id="output"></div>

JS Count occurrences in array and sort by highest

I'm trying to write a vote counting function, I have an array of objects and each object has a property called currentVote which has a userId value. I want to find out which userID has the most votes. Using lodash this is what I got so far:
function countVotes(players) {
return new Promise(function(resolve, reject) {
//votes should be empty, filled it with some sample values
let votes = ['312139659792875521','360445341989863434', '312139659792875521','360445341989863435','1','9999999999999999999999'];
for (let i = 0, j = players.length; i < j; i++) {
votes.push(players[i].currentVote);
}
let tally = _.chain(votes)
.countBy()
.toPairs()
.sortBy(1).reverse()
.map(0)
.value()[0];
resolve(tally);
});
How can I pick a random value IF I have multiple userIds with the same number of votes. At the moment it seems that the smallest ID will always be picked?
Based on your question, I believe your object is as follow, I have used the array method sort to sort the array in descending and picked up the first element. Hope this helps.
let players = [{
"userId":1,
"currentVotes":2220
},
{
"userId":2,
"currentVotes":383830
},
{
"userId":3,
"currentVotes":6894740
},
{
"userId":4,
"currentVotes":6894740
},
{
"userId":5,
"currentVotes":1
}
];
function getHighestVoteByRandowm(players){
let arrSameVotes = [];
let i = 0;
do{
arrSameVotes.push(players[i]);
temp = players[i].currentVotes;
i++;
}while(players[i].currentVotes == temp);
let rndTill = arrSameVotes.length - 1;
let rndVal = Math.round(Math.random() * rndTill);
return arrSameVotes[rndVal];
}
function sortVotes(a,b){
return b.currentVotes - a.currentVotes;
}
let highestVotesPlayer = getHighestVoteByRandowm(players.sort(sortVotes));
console.log(highestVotesPlayer);
You could use _.shuffle and _.first. Maybe something like:
_.chain(votes).countBy()
.groupBy() // added this to get a list of all the ones that have matching vote counts
.toPairs()
.sortBy(0)
.reverse()
.first() // most votes
.last() // get the user ids
.shuffle() // randomize order
.first() // get whatever is first
.value()

Categories

Resources