Remove specific product based on multiple factors - javascript

I am trying to remove the specific product a user is clicking on.
So far, when you are trying to remove a product from the cart it removes based on the ID the product has. Though, I need it to check size, color, and ID. I don't want it to remove both "Product A, size M" and "Product A, size L" if the user is only clicking on size M.
So for example:
If I try to remove the "size M" one, it should only remove the "size M" one, not the "size L" as well (as both of them have the same ID).
Here is my code where the deletion of a product is:
const removeItemHandler = (e) => {
let id = e.currentTarget.getAttribute("itemid");
let size = e.currentTarget.getAttribute("size");
let color = e.currentTarget.getAttribute("color");
const clonedCartItems = JSON.parse(JSON.stringify(cartItems));
// Here is where I am trying to filter out the product. So it will only take the one the user is
clicking on
let newCart = clonedCartItems.filter(
(elem) => elem.id !== id && elem.size !== size
);
setCartItems(newCart);
};
Thanks!

If using React JS, then question like this has already been asked,
trick is to pass the index, while calling removeItemHandler
Removing element from array in component state
e.currentTarget.getAttribute("itemid"); this code is dependent on the data,
Today your logic dependent on size and color, tomorrow it might be something else
Scalable code : You can assign the UUID (probably v4) while adding the stuffs to the cart and then setting it over attribute (or passing over callback with above approach), then taking the id and finding it.
let id = e.currentTarget.getAttribute("UUID");
with one line this can be generic.
sample code
codesandbox.io/s/delete-items-from-cart-g9qm5?file=/src/App.js

let newCart = clonedCartItems.filter(
(elem) => {
if(elem.id == id) {
return elem.size !== size;
}else
return elem.id !== id
}
);

Related

Two Javascript arrays

There is a product page in the store. The goods are gift card codes. Each has its own price. Cards are bought using a form with buttons for card denominations (each has its own price), which is almost completely unrelated to the product page (the form is in a pop-up, called by clicking on the button), and product cards appeared as a bonus, they were not originally planned. But since there is such a thing, it is necessary to adjust it. The essence of the task is that when you click on the popup call in the form, the button of the required card denomination is clicked. So that the parameters in the form change accordingly. I thought to cling to the url of the product page (in the url there is something like nominal-4000). But I don’t know how to make a comparison so that part of this url is compared with an array of buttons that also have the same class (of type nominal-4000). Here's what I was able to do:
const popupBtn = document.querySelector('.popup-btn');
pb.addEventListener('click', (e) => {
e.preventDefault();
document.body.classList.add('popup-open');
let nominal4000 = document.querySelector('.nominal-4000');
let field = 'nominal-4000';
if(window.location.href.indexOf(field) > -1) {
nominals.forEach(nominal => {
nominal.classList.remove('active-nominal');
if (nominal.classList.contains(field) ) {
nominal4000.click();
nominal4000.classList.add('active-nominal');
}
})
}
Here I'm just looking for the button and the url part of the page by nominal-4000. Works. But there will be 10 total products, and therefore pages and, consequently, buttons. That is, an array is needed. And their comparison, or something else. I have not delved into such wilds of JS yet, I cannot understand what and how. Use for example an array with denominations (they are also part of the url):
var fields = [
'nominal-3000',
'nominal-4000',
'nominal-5000'
];
Then an array with button classes, something like this -
var nominals = document.querySelectorAll(`${fields}`);
Here is a comparison of two arrays
let isFounded = fields.some( ai => nominals.includes(ai) );
But it doesn't all work together. Who fumbles in arrays, help please
Try this
const popupBtn = document.querySelector('.popup-btn');
popupBtn.addEventListener('click', (e) => {
e.preventDefault();
document.body.classList.add('popup-open');
var fields = [
'nominal-3000',
'nominal-4000',
'nominal-5000'
];
var nominals = document.querySelectorAll(`.${fields.join(', .')}`);
fields.forEach(field => {
if(window.location.href.indexOf(field) > -1) {
nominals.forEach(nominal => {
nominal.classList.remove('active-nominal');
if (nominal.classList.contains(field) ) {
nominal.click();
nominal.classList.add('active-nominal');
}
})
}
});
});

JSON Parse error undefined variable u in the beggning / can not read subSubItems${i} while repeater data has values

I am kinda new to the Velo coding / javascript in general and I am trying to re-create this tutorial --> https://support.wix.com/en/article/velo-tutorial-creating-an-expanding-mega-menu
Without the second menu (only a main menu and a strip with the items like attached screenshot).
I have a problem with javascript and wix coding. Even though I have created the collections correctly for some reason I can not open the site menu correctly. I am also attaching a wix forum link: https://www.wix.com/velo/forum/coding-with-velo/typeerror-cannot-read-properties-of-undefined-reading-filter.
Can not read the data subSubItems{i} from repeaterData, while it has all the necessary data in it
I am also attaching a screenshot of the database inself for review. (Json format on subSubItems) and the wix site itself as of right now: https://giannisliko.wixsite.com/my-site-1
The global page coding is this:
// The code in this file will load on every page of your site
//-------------Imports-------------//
import wixData from 'wix-data';
//-------------Global Variables-------------//
//Number of Submenu 2 repeaters.
const subLevel2RepeaterCount = 5;
//Object containing all menu data from subTitles database collection.
let menuData;
$w.onReady(async () => {
//Get the menu data from the collection.
menuData = await wixData.query("SubTitlesCollection").find().then(result => result.items);
//console.log(menuData);
//Set up each Submenu 2 repeater as it is loaded.
for (let i = 1; i <= subLevel2RepeaterCount; i++) {
$w(`#repeaterSubSub${i}`).onItemReady(($item, itemData, index) => {
//Get the repeater button from its ID.
const repeaterButton = $item(`#buttonSubLevelTwo${i}`)
//Set the item label.
repeaterButton.label = itemData.label;
//Set the item link.
repeaterButton.link = itemData.url;
});
}
});
export function buttonMainMenu_mouseIn(event) {
//Get the ID of the Submenu 1 button the mouse hovers over.
const selectedRootId = event.context.itemId;
//Get all the data of the Submenu 2 related to Submenu 1.
const repeaterData = menuData.filter(item => item.menu === selectedRootId);
const repeaterData2 = menuData.filter(item => item._id === selectedRootId);
console.log(repeaterData2);
//Set up the box element corresponding to the selected button in Submenu 2.
setSubSubMenu(repeaterData);
//Show the Submenu 2 box.
$w('#megaMenuStrip').expand();
}
export function repeaterMainMenu_mouseOut(event) {
}
function createUniqueId() {
//Creating a Unique Id for each of the menu sub-items by getting the current millisecond and adding a random number from 1 to 1000
let id = String(+new Date() + Math.floor(Math.random() * 1000))
return id;
}
function setSubSubMenu(repeaterData) {
//Set the image of the Submenu 1
//$w('#rangeMenuImage').src = repeaterData.img1;
for (let i = 1; i <= subLevel2RepeaterCount; i++) {
//Convert the Submenu 2 string to a Javascript object.
console.log(repeaterData);
console.log(repeaterData[`subSubItems1`]);
const dataSubSub = JSON.parse(repeaterData[`subSubItems${i}`]);
//Set a unique ID for each item.
console.log(dataSubSub);
dataSubSub.forEach(subSubItem => {
subSubItem._id = createUniqueId();
})
//Set the Submenu 2 data in the repeater.
$w(`#repeaterSubSub${i}`).data = dataSubSub;
}
}
export function megaMenuStrip_mouseOut(event) {
$w('#megaMenuStrip').collapse();
}
/**
* Adds an event handler that runs when the mouse pointer is moved
onto the element.
You can also [define an event handler using the Properties and Events panel](https://support.wix.com/en/article/velo-reacting-to-user-actions-using-events).
[Read more](https://www.wix.com/corvid/reference/$w.Element.html#onMouseIn)
* #param {MouseEvent} event
*/
/**
* Sets the function that runs when a new repeated item is created.
[Read more](https://www.wix.com/corvid/reference/$w.Repeater.html#onItemReady)
* #param {$w} $item
*/
Thank you very much in advance
I can't say for sure what's going on, but I can try to point you in the right direction.
If repeaterData is undefined, that means something is probably going wrong on the following line:
const repeaterData = menuData.filter(item => item._id === selectedRootId)[0]
The problem there could be that menuData is undefined, which would mean your query is no good.
Or it could be that none of the item IDs match the selectedRootId. I'm guessing that is the case. Looks like in the tutorial they aren't try to match with item._id like you are doing. It's really hard to tell exactly what's wrong there, but I'm pretty sure that's where your issue is. It could be a problem with your repeater IDs or it could be with the data coming from the collection. Either way, you're not getting any matches there.

DataTable rows.every function Issue

I am creating an attendance tracker with the jQuery DataTables plugin! I have gotten really far with the functionality/capability and have just been stuck for weeks trying to figure out how to do this last portion of what I want it to do.
I will have a static/workable test case attached below. So the issue that I cannot figure out is how to style the parent rows based off of the child row cell values. The columns Sunday-Friday are colored based off of a hidden value called SundayStatus, MondayStatus, TuesdayStatus, and so on. There are two values that could cause it to turn green (TW & P), two values that could cause it to turn yellow (NR & O), and two values to cause it to turn red (PTO & H). In my rows.every(function ( rowIdx, tableLoop, rowLoop ) { function I need to find a way to manipulate the data and add classes to the parent rows based off the attendance values from each individual day.
P.S.(I created my own plugin $.fn.dataTable.ext.search.push(function to search through all of the data in the table and only show items where the dates Sunday-Friday are dates that are in the current week.
UPDATE 5/10 Andrew was on the right track with the update to his answer, I made one small change to today format, and changed var result = Object.keys(data).find(key => data[key].substring(0,10) === today); to var result = Object.keys(data).find(key => typeof data[key] === 'string' && data[key].startsWith(today));. I then created a conditional in my dynamic code, to read through the result from the reverse-lookup and depending on what the result is, to color the row a certain color.
Here is my JSFiddle of the Static Example that was previously in a snippet within the post: https://jsfiddle.net/BeerusDev/y8t0xoze/19/
In this update, my last and final issue that I am dealing with that I did not foresee, is that everything seems to be working fine, but it appends the status class from the first item that is posted to the DataTable and doesn't take into account for the other items. I have hit a mental block trying to figure out a way around this issue, but here is my rows.every function from my dynamic application which is inside of my startRender function
var statusClass = '';
rows.every(function ( rowIdx, tableLoop, rowLoop ) {
var data = this.data();
var node = this.node();
var today = moment().format("YYYY-MM-DD"); // "05/10/2021"
console.log(today);
//console.log(JSON.stringify(data));
var result = Object.keys(data).find(key => typeof data[key] === 'string' && data[key].startsWith(today)); // "Monday"
console.log(result);
var todayStatus = result ? data[result + 'Status'] : 'n/a';
console.log(todayStatus);
if(todayStatus === "P" || todayStatus === "TW") {
statusClass = 'green';
}
if(todayStatus === "NR" || todayStatus === "O") {
statusClass = 'yellow';
}
if (todayStatus === "PTO" || todayStatus === "H") {
statusClass = 'red';
}
});
//Add category name to the <tr>.
return $('<tr/>').addClass(statusClass)
.append('<td colspan="8">' + group + ' (' + rows.count() + ')</td>')
.attr('data-name', all)
.toggleClass('collapsed', collapsed);
This looks very close, to me!
Here are some changes I recommend:
After the end of your closing </table> tag, there is an extra <body> tag. That looks incorrect - it should be removed. I don't think this causes any errors - but it is worth fixing.
In your rows.every() function, the data variable is a plain array - for example:
[ "IT", "Name 1", "Locations Here", "05/02/2021", "05/03/2021", "P", … ]
Therefore you cannot use data.MondayStatus - because that will be undefined. Instead use something like data[5] to get the 6th item in the array (P).
If you want to change the background color of a row for a location (e.g. "IT" or "OM"), you can use a selector like this:
$("tr[data-name='IT'] td").addClass("green");
This works because you have already added a custom attribute called data-name to the relevant <td> tag. The selector finds the <td> tag which is the child of the <tr> tag using that custom attribute.
However, the problem here is: You are trying to assign the class to a table node before the DataTable has finished being built.
To address this you can move all of that row looping logic to an initComplete function:
initComplete: function(settings, json) {
this.api().rows().every(function ( rowIdx, tableLoop, rowLoop ) {
var data = this.data();
var node = this.node().previousSibling; // to handle your row grouping
if (node !== null) {
if (data[5] === "P") {
var selectorVar = "[data-name='" + data[0] + "'] td";
$( selectorVar ).addClass("green");
}
}
});
}
Instead of if (data[5] === "P"), you can expand this logic to handle different values and also different class names (not just "green"), for whatever the overall logic is that you need. My logic is just a small demo to show the color change.
Update to handle "today"
To show the approach, let's assume the following record:
var data = {
"Department": "IT",
"Name": "Name 1",
"Locations": "Locations Here",
"Sunday": "2021-05-09",
"Monday": "2021-05-10",
"MondayStatus": "P",
"Tuesday": "2021-05-11",
"TuesdayStatus": "Q",
"Wednesday": "2021-05-12",
"WednesdayStatus": "R",
"Thursday": "2021-05-13",
"ThursdayStatus": "S",
"Friday": "2021-05-14",
"FridayStatus": "T"
};
This data variable is what I think you are handling in the rows.every function. So, it's the equivalent of var data = this.data();. I may have got some of the keys wrong (uppercase/lowercase) - but you can adjust the test data if that is the case.
Now, I get today's date, formatted to match the same format as the dates in the data object:
var today = moment().format("YYYY-MM-DD"); // "2021-05-10"
I use this value to find the equivalent value in the data variable, and I return the key name for that entry:
var result = Object.keys(data).find(key => data[key].substring(0,10) === today); // "Monday"
This is basically a reverse-lookup from what you would normally do. Instead of starting with a key, we start with a value and end with a key - in this case, the key is the string "Friday".
Now we take this string and append "Status" to it.
This gives us an actual key string: "FridayStatus".
Now we use that key to find the status for today (if it exists at all in the data object):
var todayStatus = result ? data[result + 'Status'] : 'n/a'; // "P"
If the date does not exist, then you will end up with a status of "n/a".
Overall, this gives us a quick way to get today's status, without having to perform lots of if/else logic.
Once you have today's status you can use it in a smaller if/else to choose the required color you want to apply to the row.

How to remove value from array using index (Ant Design specific)?

I am creating a questionnaire type form using ReactJs and Ant Design. It is a follow up question of How to create a questionnaire type form using Ant Design?
Now I am succeeded in adding new questions and their respective answers but not in removing them. Let's suppose I have added three questions and when I am trying to remove any one of them, its always removing the last one. The related code for removing is as follows:
remove = k => {
console.log(k);
const { form } = this.props;
// can use data-binding to get
const keys = form.getFieldValue("keys");
// We need at least one passenger
if (keys.length === 1) {
return;
}
keys.splice(k, 1);
// can use data-binding to set
form.setFieldsValue({
keys: keys
});
console.log(keys);
};
The complete code can be found as a demo on codesandbox.io.
I have done something similar in the past. Got rid of the boilerplate of antd's remove and replaced with this. Every time I add a row I push that row (object) to formRows array then removing like this:
remove = key => {
const newRows = this.state.formRows.filter(r => r.key !== key)
this.setState(
prev => ({
formRows: newRows
})
)
}

Pick random value from firebase snapshot

I'm using firebase's foreach to get each child in a tree from this url
Objective, when the page loads grab a random item from firebase and show it
data structure
grabbit (table name)
active (for active items for sale)
category (the category of the item ie womensClothes, MensShoes etc)
unique id of the item
On page load go into http://gamerholic.firebase.com/grabbit/active
and grab any one of the categories and return it..
Script
var grabbitRef = new Firebase('https://gamerholic.firebaseIO.com/grabbit/active/');
grabbitRef.on('value', function(snapshot) {
if(snapshot.val() === null) {
alert("invalid");
} else {
// get snap shot data:
snapshot.forEach(function(snapshot) {
var name = snapshot.name();
alert(name);
});
}
});
After I have a random category say "electronics", I get a new snapshot and have it return any random item that's in electronics
var grabbitRef = new Firebase('https://gamerholic.firebaseIO.com/grabbit/active/'+name);
grabbitRef.on('value', function(snapshot) {
if(snapshot.val() === null) {
alert("invalid");
} else {
// get snap shot data:
snapshot.forEach(function(snapshot) {
var id = snapshot.name();
alert(id);
});
}
});
with the id I can now get the details of the item
var grabbitRef = new Firebase('https://gamerholic.firebaseIO.com/grabbit/active/'+name+'/'+id);
It's not possible to grab a random item from the list in Firebase, unfortunately. You can do limit(1) to grab the first item, or endAt().limit(1) to grab the last item.
If you're using forEach, you can also grab all the items like you are and then picking one at random, using Math.random. For example:
var i = 0;
var rand = Math.floor(Math.random() * snapshot.numChildren());
snapshot.forEach(function(snapshot) {
if (i == rand) {
// picked random item, snapshot.val().
}
i++;
});
One way to implement this is to store an additional child attribute with each element of your list that will take on a random value. Let's call the name of this attribute "randomVal".
To pick your random entry you would use orderByChild("randomVal") and then limit the query to returning exactly one entry. Immediately upon fetching this entry, you would write a new random value into the "randomVal" element.
Beyond the additional bookkeeping work, the biggest downside of this approach is that it requires a write to the database every time you want to select a random element. I'm new to firebase, so I don't know how significant this drawback is.
Also, make sure to index this part of the database on "randomVal" to improve the query performance.

Categories