Add product ratings to an Array of objects JavaScript - javascript

I have an Array of Objects containing different product names. Each object also contains a rating (1 star, 2 stars, 3 stars, 4 stars, 5 stars).
let myProducts = [
{
productName: "Name of the product",
rating: '5 Stars',
},
{
productName: "Name of the product",
rating: '4 Stars',
},
{
productName: "Name of the product",
rating: '3 Stars',
},
{
productName: "Name of the product",
rating: '5 Stars',
},
{
productName: "Name of the product",
rating: '4 Stars',
},
]
As well as the number of stars shown, I also want to include individual ratings. The user should be able to see each individual rating, the user who wrote that rating and the text included in that rating.

You can add an array to each item with the individual ratings. This architecture can help you:
let myProducts = [
{
productName: "Name of the product",
rating: '5 Stars',
individualRatings: [
{
rating: 5,
user: "John Doe",
text: "I really enjoyed this product!"
},
{
rating: 4,
user: "Jane Doe",
text: "It was ok."
}
]
},
{
productName: "Name of the product",
rating: '4 Stars',
individualRatings: [
{
rating: 4,
user: "John Doe",
text: "I really enjoyed this product!"
},
{
rating: 3,
user: "Jane Doe",
text: "It was ok."
}
]
},
]
Extra: Then you can also generate an average between all the IndividualRatings to get the final rating of the product. Also you can delete the general rating and calculate this in the client side maping rating in IndividualRatings (ex: IndividualRatings[x].rating)

Related

How to merge one object id with same value into new array javascript [duplicate]

This question already has answers here:
Group objects by property in javascript
(8 answers)
Closed 2 months ago.
i have array of object transaction join with product and user table, i want to combine id with same value so it can display two different data in 1 object
Here's my data
let test = [
{
TransactionId: 1, //transaction table
username: "A", //user table
qty: 3, //product table
product_name: "Logitech G733",
price: $100,
description: "Lalalalala",
productId: 10
},
{
TransactionId: 2,
username: "B",
qty: 1,
product_name: "Razer",
price: $200,
description: "Blalalala",
productId: 12
},
{
TransactionId: 1,
username: "A",
qty: 1,
product_name: "Mousepad",
price: $50,
description: "This is mousepad",
productId: 7
},
{
TransactionId: 3,
username: "C",
qty: 2,
product_name: "Headphone",
price: $300,
description: "This is Headphone",
productId: 2
},
]
this is the output i want
let test = [
{
TransactionId: 1,
username: "A",
qty: [3, 1],
product_name: ["Logitech G733", "Mousepad"],
price: [$100, $50]
description: ["Lalalalala", "This is mousepad"],
productId: [10, 7]
},
{
TransactionId: 2,
username: "B",
qty: 1,
product_name: "Razer",
price: $200,
description: "Blalalala",
productId: 12
},
{
TransactionId: 3,
username: "C",
qty: 2,
product_name: "Headphone",
price: $300,
description: "This is Headphone",
productId: 2
},
]
i tried using reduce and Object.assign but the output only shows object with "Mousepad" not make array ["logitech G733","Mousepad"]
there should be many ways to do it, I used a map to combine the transactions and you can do whatever you need for the map after. For example
const test = [
{
TransactionId: 1, //transaction table
username: "A", //user table
qty: 3, //product table
product_name: "Logitech G733",
price: 100,
description: "Lalalalala",
productId: 10
},
{
TransactionId: 2,
username: "B",
qty: 1,
product_name: "Razer",
price: 200,
description: "Blalalala",
productId: 12
},
{
TransactionId: 1,
username: "A",
qty: 1,
product_name: "Mousepad",
price: 50,
description: "This is mousepad",
productId: 7
},
{
TransactionId: 3,
username: "C",
qty: 2,
product_name: "Headphone",
price: 300,
description: "This is Headphone",
productId: 2
},
]
const tMap = new Map();
test.forEach(transation => {
tMap.set(transation.TransactionId, { ...tMap.get(transation.TransactionId), ...transation });
})
If you wan to deep combined you can use some tool like lodash deep merge
tMap.set(transation.TransactionId, _.merge(tMap.get(transation.TransactionId), transation))
Then you have a map based on your tranastion Id, and you can decide what to do next. If you wan the array back you can simple run
console.log(Array.from(tMap.values()));

Generate a total price from the items in state and output it in JSX (React)

I have data in an array of objects:
const data = [
{
id: 1,
category: "tables",
name: "N/A",
price: 0,
},
{
id: 2,
category: "tables",
name: "Table 1",
price: 220,
},
{
id: 3,
category: "tables",
name: "Table 2",
price: 420,
},
{
id: 4,
category: "tables",
name: "Table 3",
price: 515,
},
{
id: 5,
category: "tables",
name: "Table 4",
price: 495,
},
{
id: 6,
category: "tables",
name: "Table 5",
price: 210,
},
{
id: 7,
category: "chairs",
name: "N/A",
price: 0,
},
{
id: 8,
category: "chairs",
name: "Chair 1",
price: 75,
},
{
id: 9,
category: "chairs",
name: "Chair 2",
price: 150,
},
{
id: 10,
category: "desks",
name: "Desk 1",
price: 75,
},
{
id: 11,
category: "desks",
name: "Desk 2",
price: 130,
},
{
id: 12,
category: "desks",
name: "Desk 3",
price: 215,
},
{
id: 13,
category: "desks",
name: "Desk 4",
price: 275,
},
{
id: 14,
category: "lighting",
name: "Lighting 1",
price: 105,
},
{
id: 15,
category: "lighting",
name: "Lighting 2",
price: 150,
},
];
export default data;
I have a reducer which updates the state depending on which items the user selects on the page (via radios, checkboxes and quantity inputs). Here's what the initial state looks like. The nested keys correspond to the ids in data and the values are the quantities, e.g. there are two desks currently selected (with ids 10 and 12, and 1 quantity of each). Lighting has x2 of id 14 and id 15 has its quantity set to zero as this is output on the page as the initial value in a quantity input.
const [reducerState, dispatch] = useReducer(reducer, {
tables: {
1: 1,
},
chairs: {
7: 1,
},
desks: {
10: 1,
12: 1,
},
lighting: {
14: 2,
15: 0,
},
});
What I need to do is calculate a total price based on the ids and quantities in state. In this example it should be £500. How can I generate this and output it on the page in the JSX?
Any help appreciated, thanks.
Here's a working example:
You have to create a reducer function which goes through every selected option, finds that id in the data and then adds the count*price to the sum so far.
https://codesandbox.io/s/keen-sammet-b5m3y9?file=/src/App.js
I do not know what your reducer switch does, but the logic to check and eventually add the price could be:
const totalPriceForType=(data,initState) => data.map(item=>
initState.map(id=>
item.id===id && item.price+=item.price))

Update multiple product values with one dataLayer.push

Say I have the following dataLayer:
{
ecommerce: {
currencyCode: "USD",
purchase: {
actionField: {
id: "1a6d5021",
affiliation: "Online Store",
revenue: 40,
tax: 0,
shipping: "",
coupon: ""
},
products: [
{
name: "Product 1",
id: "123",
price: 40,
category: null,
quantity: 1,
coupon: "disc10",
type: "Service A"
},
{
name: "Product 4",
id: "456",
price: 40,
category: null,
quantity: 1,
coupon: "disc10",
type: "Service B"
}
]
}
}
}
So in the product array, category always has value null. How can I push the same value as type respectively for each product, whilst leaving everything else in the dataLayer untouched?
Ultimately the final result that I am trying to achieve would be like this:
{
ecommerce: {
currencyCode: "USD",
purchase: {
actionField: {
id: "1a6d5021",
affiliation: "Online Store",
revenue: 40,
tax: 0,
shipping: "",
coupon: ""
},
products: [
{
name: "Product 1",
id: "123",
price: 40,
category: "Service A",
quantity: 1,
coupon: "disc10",
type: "Service A"
},
{
name: "Product 4",
id: "456",
price: 40,
category: "Service B",
quantity: 1,
coupon: "disc10",
type: "Service B"
}
]
}
}
}
It be easy with a single product, but I quite can't find how to do it when multiple products.
Thanks in advance for your help.
If I understand your requirement correctly that you want to assign the type value in the category for each products object. If Yes, Its a straight forward.
Working Demo :
const productObj = {
ecommerce: {
currencyCode: "USD",
purchase: {
actionField: {
id: "1a6d5021",
affiliation: "Online Store",
revenue: 40,
tax: 0,
shipping: "",
coupon: ""
},
products: [{
name: "Product 1",
id: "123",
price: 40,
category: null,
quantity: 1,
coupon: "disc10",
type: "Service A"
},
{
name: "Product 4",
id: "456",
price: 40,
category: null,
quantity: 1,
coupon: "disc10",
type: "Service B"
}
]
}
}
};
productObj.ecommerce.purchase.products.forEach((obj) => obj.category = obj.type);
console.log(productObj);
There are two options.
Push the whole ecommerce object again, with all fields set now. It results in a bit of a mess in DL and certain timing issues one has to keep in mind when implementing tracking.
Remove/delay the first ecommerce push till you have all info and only push the ecommerce object once.
In most cases, 2 is the best option. 1 can be justified when the event relying on the ecommerce object has to fire before categories become available to the front-end.
Try
function createCategoryFn(category) {
return (properties) => {
return {
name: "",
id: "",
price: 0,
category: category,
quantity: 1,
coupon: "",
type: category,
...properties
};
};
}
const createSportsProduct = createCategoryFn('Sports');
const tennisProduct = createSportsProduct({ name: 'tennis racket', id: 1, price: 100 });
const basketballProduct = createSportsProduct({ name: 'basketball', id: 2, price: 100 });
console.log(tennisProduct);
console.log(basketballProduct)

Pushing array without duplicate and change the property value of object in Javascript?

I have an object and i'm pushing into array while pushing i need to restrict the duplicate and also if there is any changes in the property then update the array accordingly ?
[{
Id: "a134",
Name: "Name -",
Company: "001",
Product :"01"
quantity :1
},
{
Id: "a135",
Name: "Name -1",
Company: "002",
Product :"03"
quantity :2 -----> (Previous event.target.name)
},
{
Id: "a135",
Name: "Name -1",
Company: "002",
Product :"03"
quantity :3 ---> (current event.target.name)
}
]
if i'm pushing into array there might be chance to update quantity how to achieve the below result
[{
Id: "a134",
Name: "Name -",
Company: "001",
Product :"01"
quantity :1
},
{
Id: "a135",
Name: "Name -1",
Company: "002",
Product :"03"
quantity :3 ---> (current event.target.name)
}
]
and now my code is
if(event.target.value!='')
{
const searchObj = this.myList.find(({ Id,Product, Company }) => Product === index);
if (searchObj)
{
console.log('searchObj',searchObj);
resultVal = { ...searchObj, quantity:parseInt(event.target.value)};
if (!this.newProductList.some(e => e.Product === resultVal.Product))
{
this.newProductList.push(resultVal);
}
}
}
I think an array is the wrong data type. I would prefer using a map.
This of course only works if the Id is unique since that is what is best used as key:
const myMap = new Map([["a134",{
Name: "Name -",
Company: "001",
Product :"01",
quantity :1
}]]);
And then it is easy to check if an item is already present, before updating the quantity or adding a new item.
const id = "a134"; // or "a135" for a new entry
const newItem = { Name: "Name B",
Company: "002",
Product :"012",
quantity :1
}
if(myMap.has(id)){
const item = myMap.get(id);
myMap.set(id, {...item, quantity: item.quantity +1})
} else {
myMap.set(id,newItem);
}
console.log(myMap) // Map {'a134' => { Name: 'Name A', Company: '001', Product:'01', quantity: 2 } }
This is best solved by using a different data structure: use a plain object, keyed by Id:
let data = {
"a134": {
Id: "a134"
Name: "Name -",
Company: "001",
Product: "01"
quantity: 1
},
"a135": {
Id: "a135",
Name: "Name -1",
Company: "002",
Product: "03"
quantity: 2
},
};
To update/add don't push, but set the object key's value. For example:
// Let's say we want to add/update with this object:
let objToAdd = {
Id: "a135",
Name: "Name -1",
Company: "002",
Product: "03"
quantity: 3
}
// ...then just do:
data[objToAdd.Id] = objToAdd;
This will either update or "insert". In the above case, it will update:
let data = {
"a134": {
Id: "a134"
Name: "Name -",
Company: "001",
Product: "01"
quantity: 1
},
"a135": {
Id: "a135",
Name: "Name -1",
Company: "002",
Product: "03"
quantity: 3
},
};
If you ever need the array-format, then just do:
let arr = Object.values(data);
...but trying to stick with the array is a guarantee for inefficient code. It just isn't the right tool for the job here. You should adapt your code to work with the plain object representation throughout. You can iterate over the values in an object, you can remove items from an object, update, add, ...etc.

How to add items to an array according to its category?

I have a page that is a simulation of a clothing store. The list of clothes displayed is divided into five different categories.
The user has the option to click on the Add Clothes button and add a new clothes to the list that already exists.
My question is how to add a new item to the clothing array according to the category that the user chose?
For example, if he chooses to add a hat, add the new item to the hat collection within the array.
Here''s my code I put in CodeSandBox: https://codesandbox.io/s/stupefied-flower-1ij9v?file=/src/App.js
Here's my shop data:
const shop_data = [{
id: 1,
title: "Hats",
routeName: "hats",
items: [{
id: 1,
name: "Brown Brim",
imageUrl: "https://i.ibb.co/ZYW3VTp/brown-brim.png",
price: 25
},
{
id: 2,
name: "Blue Beanie",
imageUrl: "https://i.ibb.co/ypkgK0X/blue-beanie.png",
price: 18
},
{
id: 3,
name: "Brown Cowboy",
imageUrl: "https://i.ibb.co/QdJwgmp/brown-cowboy.png",
price: 35
}
]
},
{
id: 2,
title: "Sneakers",
routeName: "sneakers",
items: [{
id: 10,
name: "Adidas NMD",
imageUrl: "https://i.ibb.co/0s3pdnc/adidas-nmd.png",
price: 220
},
{
id: 11,
name: "Adidas Yeezy",
imageUrl: "https://i.ibb.co/dJbG1cT/yeezy.png",
price: 280
},
{
id: 12,
name: "Black Converse",
imageUrl: "https://i.ibb.co/bPmVXyP/black-converse.png",
price: 110
}
]
},
{
id: 3,
title: "Jackets",
routeName: "jackets",
items: [{
id: 18,
name: "Black Jean Shearling",
imageUrl: "https://i.ibb.co/XzcwL5s/black-shearling.png",
price: 125
},
{
id: 19,
name: "Blue Jean Jacket",
imageUrl: "https://i.ibb.co/mJS6vz0/blue-jean-jacket.png",
price: 90
},
{
id: 20,
name: "Grey Jean Jacket",
imageUrl: "https://i.ibb.co/N71k1ML/grey-jean-jacket.png",
price: 90
}
]
},
{
id: 4,
title: "Womens",
routeName: "womens",
items: [{
id: 23,
name: "Blue Tanktop",
imageUrl: "https://i.ibb.co/7CQVJNm/blue-tank.png",
price: 25
},
{
id: 24,
name: "Floral Blouse",
imageUrl: "https://i.ibb.co/4W2DGKm/floral-blouse.png",
price: 20
},
{
id: 25,
name: "Floral Dress",
imageUrl: "https://i.ibb.co/KV18Ysr/floral-skirt.png",
price: 80
}
]
},
{
id: 5,
title: "Mens",
routeName: "mens",
items: [{
id: 30,
name: "Camo Down Vest",
imageUrl: "https://i.ibb.co/xJS0T3Y/camo-vest.png",
price: 325
},
{
id: 31,
name: "Floral T-shirt",
imageUrl: "https://i.ibb.co/qMQ75QZ/floral-shirt.png",
price: 20
},
{
id: 32,
name: "Black & White Longsleeve",
imageUrl: "https://i.ibb.co/55z32tw/long-sleeve.png",
price: 25
}
]
}
];
export default shop_data;
Can someone help me? Thank you in advance.
Pass a callback function to DialogSelect which will take the item and the category as parameters, then update the state.
In ShopPage create an addItem function
addItem = (item, category) => {
this.setState((prevState) => ({
collections: prevState.collections.map((collection) => {
if (collection.routeName === category) {
return {
...collection,
items: collection.items.concat({
...item,
// setting the id to the length of the array
// can cause problems, use an id generator of
// some sort
id: collection.items.length + 1
})
};
}
return collection;
})
}));
};
then pass it to DialogSelect
<DialogSelect addItem={this.addItem} />
In DialogSelect call the callback from props when the user is adding an item
const addClothes = () => {
const item = { product, price, imageUrl };
addItem(item, category);
};
sandbox
I see two solutions, the first one would be to pass the results from your DialogSelect component to the parent (ShopPage) by using a callback in the props:
<DialogSelect onAddClothes={this.onAddClothes} />
Then, in this.onAddClothes function, you can update your collections through a setState() call. Use a findIndex on collections to find the object having "hats" as a routeName and add your item in the items array with a push() call.
The second solution would be to use Redux in order to have a general store for your application (this could be interesting especially for a shopping website).
Hi i made a few changes to your code.
https://codesandbox.io/s/vigorous-babbage-pwmn1
You need to update your state when data send for this I made a function which update the state by category. If the category matches then add the item in the list
addNewClothes = (clothes) => {
const updatedCollections = this.state.collections;
updatedCollections.map((collection) => {
//if collection routerName eques to category
// then update the collection
if (collection.routeName === clothes.category) {
//add new Item in items
collection.items.push({
id: collection.items.length + 1,
name: clothes.product,
price: clothes.price,
imageUrl: clothes.imageUrl
});
//return updated collection
return collection;
} else {
// return original collection
return collection;
}
});
//update the state
this.setState({
collections: updatedCollections
});
};

Categories