Reputation: 1099
I have a product form which I would like users to add variants of this product to. My object for the main settings
{
title: 'Bike',
settings: {
options: [
{
title: 'Size',
values: ['60cm', '80cm', '120cm']
},
{
title: 'Color',
values: ['White', 'Black', 'Red']
}
],
variants: []
}
};
So for each option, I need a variant with each title and it's value - which will be regenerated and passed back to the .settings.variants above.
I have created a Stackblitz https://stackblitz.com/edit/angular-pi27mf
In this method I need to generate a brand new variants[], right now I only understand how to generate something like
{Size: "60cm", Color: "White", Image: "img.png"},
{Size: "60cm", Color: "Black", Image: "img.png"},
{Size: "60cm", Color: "Red", Image: "img.png"},
By just looping through one of the options.. but how can I loop though all options and create a new variant for each possible value?
The model I would need to achieve would be this
{Size: "60cm", Color: "White", Image: "img.png"},
{Size: "60cm", Color: "Black", Image: "img.png"},
{Size: "60cm", Color: "Red", Image: "img.png"},
{Size: "80cm", Color: "White", Image: "img.png"},
{Size: "80cm", Color: "Black", Image: "img.png"},
{Size: "80cm", Color: "Red", Image: "img.png"},
{Size: "120cm", Color: "White", Image: "img.png"},
{Size: "120cm", Color: "Black", Image: "img.png"},
{Size: "120cm", Color: "Red", Image: "img.png"},
Keeping in mind that Size
and Color
are dynamic and could be changed by the user, so the function can't just depend on this amount/type of options.
I am sure there is some array math that needs to be going on but if someone could point me in the right direction or re-create a stackblitz for me it would be a massive help.
Upvotes: 1
Views: 274
Reputation: 35259
You can create an array of title
and a 2D array of values
array using map
. Then create a Cartesian product of all the values
. Then loop through the all the combinations and create objects using reduce
. Use { Image: "img.png" }
as the initialValue
parameter. This will work for any number of objects inside options
array
const input = { title: 'Bike', settings: { options: [{ title: 'Size', values: ['60cm', '80cm', '120cm'] }, { title: 'Color', values: ['White', 'Black', 'Red'] }], variants: [] } }
const { options } = input.settings,
titles = options.map(o => o.title),
values = options.map(o => o.values),
defaultObject = { Image: "img.png" }
// https://stackoverflow.com/a/57597533/3082296
const combos = values.reduce((acc, curr, i) =>
acc.flatMap(c => curr.map(n => [].concat(c, n)))
)
const createObject = values =>
titles.reduce((acc, k, i) => {
acc[k] = values[i];
return acc
}, defaultObject)
const output = combos.map(createObject)
console.log(...output)
Upvotes: 1
Reputation: 386883
You could take the keys and values from data, generate the cartesian product from values and create key/value pairs as result.
var data = { title: 'Bike', settings: { options: [{ title: 'Size', values: ['60cm', '80cm', '120cm'] }, { title: 'Color', values: ['White', 'Black', 'Red'] }], variants: [] } },
keys = data.settings.options.map(({ title }) => title).concat('Image'),
values = data.settings.options.map(({ values }) => values).concat([['img.png']]),
cartesian = values
.reduce((a, b) => a.reduce((r, v) => r.concat(b.map(w => [].concat(v, w))), []))
.map(a => Object.assign({ title: a.slice(0, -1).join('/') }, ...keys.map((k, i) => ({ [k]: a[i] }))));
console.log(cartesian);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Upvotes: 1
Reputation: 10662
Try this:
generateVariants() {
const options = [...this._form.settings.options];
const sizeOptions = options[0].values;
const colorOptions = options[1].values;
const regeneratedVariants = [];
for(let i=0;i< sizeOptions.length;i++) {
for(let j=0;j< colorOptions.length;j++) {
regeneratedVariants.push({
Size: sizeOptions[i],
Color: colorOptions[i],
Image: "img.png"
})
}
}
console.log(regeneratedVariants);
}
this will produce an array with all the variants possible with sizes and colors.
Upvotes: 0