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)
Related
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))
Ahoy,
i am using built in gtm plugin on wordpress/woocomerce and it gets the following content:
cartContent: {
totals: {
applied_coupons: [],
discount_total: 0,
subtotal: "2844.715447",
total: "2844.715447"
},
items: [
{
id: "K-GG-V4-S",
name: "Grill Gazowy Koler Relish v4 5 palników 17,2kW",
sku: "K-GG-V4-S",
category: "Grille Gazowe",
price: 3499,
stocklevel: 41,
quantity: 1
},
{
id: "5900000002453",
name: "Fartuch Koler",
sku: "5900000002453",
category: "Wszystkie produkty",
price: 0,
stocklevel: null,
quantity: 1
},
{
id: "6600006666664",
name: "Pokrowiec + wąż i reduktor",
sku: "6600006666664",
category: "Wszystkie produkty",
price: 0,
stocklevel: null,
quantity: 1
}
]
},
but I have to implement the entire content of the basket into something that is to change dynamically depending on the number of products:
<script>
wph('track', 'AddToCart', {
content_type: 'category',
contents: [{
id: 'PRODUKT_ID1',
name: 'NAZWA_PRODUKTU1',
category: 'KATEGORIA_PRODUKTU1',
ean: 'PRODUKT_EAN_ID1',
price: 20.15,
in_stock: true
quantity: 1
weight : 'WAGA PRODUKTU'
}, {
id: 'PRODUKT_ID2',
name: 'NAZWA_PRODUKTU2',
category: 'KATEGORIA_PRODUKTU2',
ean: 'PRODUKT_EAN_ID2',
price: 20.15,
in_stock: true
quantity: 1
weight : 'WAGA PRODUKTU'
}]
})
</script>
How can I do this in GTM? I must admit that it was a bit too much for me, because I usually didn't need the entire basket.
I would like to populate the value 'discount' for a product with the discount ID value from the array discounts, if the respective product ID exists as a value in the Discounts object.
const products = [{
id: "05cdb75d-7984-4dbf-b0f4-d6532163b66d",
name: "SANTO - Schnürstiefelette",
price: 199.95,
discount: 0,
},
{
id: "1b9b6c7e-c856-464c-ba64-98c9dd6733b5",
name: "AIR FORCE 1 07 LV8 - Sneaker low",
price: 109.95,
discount: 0,
},
{
id: "f831aaf4-347a-458f-bb0c-21cf02aeac2e",
name: "DUFF 9.0 - Sporttasche",
price: 34.95,
discount: 0,
},
{
id: "471ad894-150b-4a2b-881c-a9a4dbc4b401",
name: "Strickpullover",
price: 20.99,
discount: 0,
},
];
const discounts = [{
id: "5791ae04-a704-4f44-808b-de5ddb8812b5",
name: "Christmas discount",
productIds: ["1b9b6c7e-c856-464c-ba64-98c9dd6733b5", "f831aaf4-347a-458f-bb0c-21cf02aeac2e"],
active: true
},
{
id: "5791ae04-a704-4f44-808b-de5ddb8812e6",
name: "Christmas discount 2",
productIds: ["05cdb75d-7984-4dbf-b0f4-d6532163b66d"],
active: true
}
];
At the end i need it like:
const products = [{
id: "05cdb75d-7984-4dbf-b0f4-d6532163b66d",
name: "SANTO - Schnürstiefelette",
price: 199.95,
discount: '5791ae04-a704-4f44-808b-de5ddb8812e6',
},
...
...
You could use map() to transform products array. And find() and includes() to check if discount exists for a product.
const products = [{ id: "05cdb75d-7984-4dbf-b0f4-d6532163b66d", name: "SANTO - Schnürstiefelette", price: 199.95, discount: 0, }, { id: "1b9b6c7e-c856-464c-ba64-98c9dd6733b5", name: "AIR FORCE 1 07 LV8 - Sneaker low", price: 109.95, discount: 0, }, { id: "f831aaf4-347a-458f-bb0c-21cf02aeac2e", name: "DUFF 9.0 - Sporttasche", price: 34.95, discount: 0, }, { id: "471ad894-150b-4a2b-881c-a9a4dbc4b401", name: "Strickpullover", price: 20.99, discount: 0, }, ];
const discounts = [{ id: "5791ae04-a704-4f44-808b-de5ddb8812b5", name: "Christmas discount", productIds: ["1b9b6c7e-c856-464c-ba64-98c9dd6733b5", "f831aaf4-347a-458f-bb0c-21cf02aeac2e"], active: true }, { id: "5791ae04-a704-4f44-808b-de5ddb8812e6", name: "Christmas discount 2", productIds: ["05cdb75d-7984-4dbf-b0f4-d6532163b66d"], active: true } ];
let result = products.map(product => {
let discount = discounts.find(item => item.productIds.includes(product.id));
return {
...product,
"discount": discount ? discount.id : product.discount
};
});
console.log(result);
You could store the discounts in a Map and map the object with a new discount object, if necessary.
var products = [{ id: "05cdb75d-7984-4dbf-b0f4-d6532163b66d", name: "SANTO - Schnürstiefelette", price: 199.95, discount: 0 }, { id: "1b9b6c7e-c856-464c-ba64-98c9dd6733b5", name: "AIR FORCE 1 07 LV8 - Sneaker low", price: 109.95, discount: 0 }, { id: "f831aaf4-347a-458f-bb0c-21cf02aeac2e", name: "DUFF 9.0 - Sporttasche", price: 34.95, discount: 0 }, { id: "471ad894-150b-4a2b-881c-a9a4dbc4b401", name: "Strickpullover", price: 20.99, discount: 0 }],
discounts = [{ id: "5791ae04-a704-4f44-808b-de5ddb8812b5", name: "Christmas discount", productIds: ["1b9b6c7e-c856-464c-ba64-98c9dd6733b5", "f831aaf4-347a-458f-bb0c-21cf02aeac2e"], active: true }, { id: "5791ae04-a704-4f44-808b-de5ddb8812e6", name: "Christmas discount 2", productIds: ["05cdb75d-7984-4dbf-b0f4-d6532163b66d"], active: true }],
ids = discounts.reduce((m, { id, productIds }) => productIds.reduce((n, pid) => n.set(pid, id), m), new Map);
products = products.map(p => Object.assign({}, p, ids.has(p.id) && { discount: ids.get(p.id) }));
console.log(products);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Nested loop through both products and discounts array, if the product id is included inside the productIds array of any of the objects in the discounts array, assign the discount id to the product discount.
for (let product of products) {
for (let discount of discounts) {
if (discount.productIds.includes(product.id)){
product.discount = discount.id;
break;
}
}
}
I have an object of object
cart {
KDR010011: {
barcode: "0"
brand: "Kapal Api"
category: "KEBUTUHAN DAPUR"
cost_price: "107569.66490299824"
cost_price_per_piece: 896.413874191652
name: "Kapal Api 25g sp mix"
product_id: "KDR010011"
qty: 1
qty_per_box: 120
selling_price: 116000
selling_price_per_piece: 962.5
},
KDR010125: {
barcode: ""
brand: "Kapal Api"
category: "KEBUTUHAN DAPUR"
cost_price: "110317.63859070961"
cost_price_per_piece: 835.7396862932546
name: "ABC Susu 31g"
product_id: "KDR010125"
qty: 5
qty_per_box: 132
selling_price: 113000
selling_price_per_piece: 863.6363636363636
}
}
and I want to remove the property, the result what I want:
cart {
KDR010011: {
qty: 1
selling_price: 116000
},
KDR010125: {
qty: 5
selling_price: 113000
}
}
I am using underscore js library, the result is this:
What should I do?
You can achieve this easily by looping over the keys of the object and assigning the value for each key back to the original object. If you don't want to modify the original object just assign the keys to a new one.
Personally I'd change my data structure so that the cart was an array of objects and each object had the KDR010011 key as a property instead.
const obj = {
KDR010011: {
barcode: "0",
brand: "Kapal Api",
category: "KEBUTUHAN DAPUR",
cost_price: "107569.66490299824",
cost_price_per_piece: 896.413874191652,
name: "Kapal Api 25g sp mix",
product_id: "KDR010011",
qty: 1,
qty_per_box: 120,
selling_price: 116000,
selling_price_per_piece: 962.5,
},
KDR010125: {
barcode: "",
brand: "Kapal Api",
category: "KEBUTUHAN DAPUR",
cost_price: "110317.63859070961",
cost_price_per_piece: 835.7396862932546,
name: "ABC Susu 31g",
product_id: "KDR010125",
qty: 5,
qty_per_box: 132,
selling_price: 113000,
selling_price_per_piece: 863.6363636363636,
}
}
Object.keys(obj).forEach(key => obj[key] = {
qty: obj[key].qty,
selling_price: obj[key].selling_price,
})
console.log(obj)
You can try this:
const newCart = {...cart}
Object.keys(newCart).forEach(key => {
newCart[key] = {
qty: newCart[key].qti,
selling_price: newCart[key].sailing_price
}
}
You need commas in your object
I have a feeling I could use destructuring better than here
const cart = {
KDR010011: {
barcode: "0",
brand: "Kapal Api",
category: "KEBUTUHAN DAPUR",
cost_price: "107569.66490299824",
cost_price_per_piece: 896.413874191652,
name: "Kapal Api 25g sp mix",
product_id: "KDR010011",
qty: 1,
qty_per_box: 120,
selling_price: 116000,
selling_price_per_piece: 962.5
},
KDR010125: {
barcode: "",
brand: "Kapal Api",
category: "KEBUTUHAN DAPUR",
cost_price: "110317.63859070961",
cost_price_per_piece: 835.7396862932546,
name: "ABC Susu 31g",
product_id: "KDR010125",
qty: 5,
qty_per_box: 132,
selling_price: 113000,
selling_price_per_piece: 863.6363636363636
}
}
let newCart = {}
Object.keys(cart).forEach(key => newCart[key] = { qty: cart[key].qty, selling_price : cart[key].selling_price })
console.log(newCart)
I have one-page web app with few arrays, that are logically linked: records from "users" refers to records in "user_types", "charges" refers to "users", etc:
var users = [
{ id: "u0001", name: "John", user_type_id: "1" },
{ id: "u0002", name: "Bob", user_type_id: "1" },
{ id: "u0003", name: "Alice", user_type_id: "5" },
{ id: "u0004", name: "Jennifer", user_type_id: "5" },
// ... more
];
var user_types = [
{ id: "1", name: "Regular Clients"},
{ id: "5", name: "VIP Clients"},
// ... more
];
var charges = [
{ id: "7443", user_id: "u0001", date: "2016-01-01", amount: "3.99", },
{ id: "7445", user_id: "u0001", date: "2016-01-01", amount: "4.02", },
{ id: "7448", user_id: "u0001", date: "2016-01-01", amount: "6.99", },
{ id: "7453", user_id: "u0003", date: "2016-01-01", amount: "3.00", },
{ id: "7469", user_id: null , date: "2016-01-01", amount: "3.99", },
// ... more
];
I need to display them in linked manner, similar to the product of following SQL:
SELECT
charges.date,
charges.amount,
users.name,
user_types.name
FROM
charges
LEFT OUTER JOIN users ON users.id = charges.user_id
LEFT OUTER JOIN user_types ON user_types.id = users.user_type_id
I know I can create API call with this SQL query on server, but I would like to avoid that because tables are already loaded in the web app.
What is the simplest way to join them in memory?
If small library is OK, this can be done with StrelkiJS:
var users = new StrelkiJS.IndexedArray();
users.loadArray([
{ id: "u0001", name: "John", user_type_id: "1" },
{ id: "u0002", name: "Bob", user_type_id: "1" },
{ id: "u0003", name: "Alice", user_type_id: "5" },
{ id: "u0004", name: "Jennifer", user_type_id: "5" },
// ... more
]);
var user_types = new StrelkiJS.IndexedArray();
user_types.loadArray([
{ id: "1", name: "Regular Clients"},
{ id: "5", name: "VIP Clients"},
// ... more
]);
var charges = new StrelkiJS.IndexedArray();
charges.loadArray([
{ id: "7443", user_id: "u0001", date: "2016-01-01", amount: "3.99", },
{ id: "7445", user_id: "u0001", date: "2016-01-01", amount: "4.02", },
{ id: "7448", user_id: "u0001", date: "2016-01-01", amount: "6.99", },
{ id: "7453", user_id: "u0003", date: "2016-01-01", amount: "3.00", },
{ id: "7469", user_id: null , date: "2016-01-01", amount: "3.99", },
// ... more
]);
var result = charges.query([{
from_col: "user_id",
to_table: users,
to_col: "id",
type: "outer",
join: [{
from_col: "user_type_id",
to_table: user_types,
to_col: "id",
type: "outer",
}]
}])
Result will be joined array of following structure:
[
[
{"id":"7443","user_id":"u0001","date":"2016-01-01","amount":"3.99"},
{"id":"u0001","name":"John","user_type_id":"1"},
{"id":"1","name":"Regular Clients"}
],
[
{"id":"7445","user_id":"u0001","date":"2016-01-01","amount":"4.02"},
{"id":"u0001","name":"John","user_type_id":"1"},
{"id":"1","name":"Regular Clients"}
],
[
{"id":"7448","user_id":"u0001","date":"2016-01-01","amount":"6.99"},
{"id":"u0001","name":"John","user_type_id":"1"},
{"id":"1","name":"Regular Clients"}
],
[
{"id":"7453","user_id":"u0003","date":"2016-01-01","amount":"3.00"},
{"id":"u0003","name":"Alice","user_type_id":"5"},
{"id":"5","name":"VIP Clients"}
],
[
{"id":"7469","user_id":null,"date":"2016-01-01","amount":"3.99"},
null,
null
]
]
If you can modify the way users and user_types are being populated then you can do this pretty quickly.
You would need to change users and user_types to objects so you have something like this:
// make users an object with the id as the key
var users = {
"u0001" : { name: "John", user_type_id: "1" },
"u0002" : { name: "Bob", user_type_id: "1" },
"u0003" : { name: "Alice", user_type_id: "5" },
"u0004" : { name: "Jennifer", user_type_id: "5" }
};
// same for user_types
var user_types = {
"1" : { name: "Regular Clients" },
"5" : { name: "VIP Clients" }
};
var charges = [
{ id: "7443", user_id: "u0001", date: "2016-01-01", amount: "3.99", },
{ id: "7445", user_id: "u0001", date: "2016-01-01", amount: "4.02", },
{ id: "7448", user_id: "u0001", date: "2016-01-01", amount: "6.99", },
{ id: "7453", user_id: "u0003", date: "2016-01-01", amount: "3.00", },
{ id: "7469", user_id: null , date: "2016-01-01", amount: "3.99", }
];
// now you can just loop through and use object key lookups:
var out = [];
for(var i = 0, numCharges = charges.length; i < numCharges; ++i)
{
var currentCharge = charges[i];
if(currentCharge.user_id === null) continue;
out.push([
currentCharge.date,
currentCharge.amount,
// get the current charges user_id and look up the name from users
users[currentCharge.user_id].name,
// same as above but use the user_type_id to get the user_type name
user_types[users[currentCharge.user_id].user_type_id].name
]);
}
console.log(out);
This proposal features IMTheNachoMan solution, with the extension of generation necessary objects from the given data.
It includes all rows of charges, because with SQL, the rows are returned too.
The problem with null values are here tested and null is then returned.
var users = [{ id: "u0001", name: "John", user_type_id: "1" }, { id: "u0002", name: "Bob", user_type_id: "1" }, { id: "u0003", name: "Alice", user_type_id: "5" }, { id: "u0004", name: "Jennifer", user_type_id: "5" }],
user_types = [{ id: "1", name: "Regular Clients" }, { id: "5", name: "VIP Clients" }],
charges = [{ id: "7443", user_id: "u0001", date: "2016-01-01", amount: "3.99", }, { id: "7445", user_id: "u0001", date: "2016-01-01", amount: "4.02", }, { id: "7448", user_id: "u0001", date: "2016-01-01", amount: "6.99", }, { id: "7453", user_id: "u0003", date: "2016-01-01", amount: "3.00", }, { id: "7469", user_id: null, date: "2016-01-01", amount: "3.99", }],
user = Object.create(null),
type = Object.create(null),
result;
users.forEach(function (u) {
user[u.id] = u;
});
user_types.forEach(function (t) {
type[t.id] = t;
});
result = charges.map(function (charge) {
return {
'charges.date': charge.date,
'charges.amount': charge.amount,
'users.name': charge.user_id === null ? null : user[charge.user_id].name,
'user_types': charge.user_id === null ? null : type[user[charge.user_id].user_type_id].name,
};
});
console.log(result);
Make users a map, so you can use users['u0001']. Then loop through charges and do users[current_charge.user_id].charges.push(current_charge). Each user in users should have a charges property initialized as an empty array. You can do that when you turn the users array into a id => user map.
You don't need anything special here, just two loops through users and charges:
var users_map = {};
var i;
for(i = 0; i < users.length; i++) {
users_map[users[i].id] = users[i];
users_map[users[i].id].charges = [];
}
for(i = 0; i < charges.length; i++) {
users_map[charge[i].user_id].charges.push(charge[i]);
}
If you really need the final "result" to be an array, not a map, you can loop through users_map again and turn it into an array.
A really simple solution leveraging modern JS stuff would be this:
var joined_data = Object.keys(users_map).map(function (key) {
return users_map[key];
});
You can make the above code a lot prettier with lodash or another similar library.
The only way to do this without restructuring the objects is to loop and filter.
You can optimise it slightly by processing the users and their types first, but that's about it...
var users = [
{ id: "u0001", name: "John", user_type_id: "1" },
{ id: "u0002", name: "Bob", user_type_id: "1" },
{ id: "u0003", name: "Alice", user_type_id: "5" },
{ id: "u0004", name: "Jennifer", user_type_id: "5" },
// ... more
];
var user_types = [
{ id: "1", name: "Regular Clients"},
{ id: "5", name: "VIP Clients"},
// ... more
];
var charges = [
{ id: "7443", user_id: "u0001", date: "2016-01-01", amount: "3.99", },
{ id: "7445", user_id: "u0001", date: "2016-01-01", amount: "4.02", },
{ id: "7448", user_id: "u0001", date: "2016-01-01", amount: "6.99", },
{ id: "7453", user_id: "u0003", date: "2016-01-01", amount: "3.00", },
{ id: "7469", user_id: null , date: "2016-01-01", amount: "3.99", },
// ... more
];
// pre-process users
var usersPlusTypes = users.map(function(u) {
var foundUserTypes = user_types.filter(function(ut) {
return ut.id == u.user_type_id;
});
return {
id: u.id,
user: u,
userType: foundUserTypes.length ? foundUserTypes[0] : null
}
})
// now link charges to users
var results = charges.map(function(c) {
var user = usersPlusTypes.filter(function(upt) {
return upt.id == c.user_id;
});
return {
date: c.date,
amount: c.amount,
userName: user.length ? user[0].user.name : null,
userTypeName: user.length && user[0].userType ? user[0].userType.name : null,
};
});
console.log(results);