1

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.

0

3 Answers 3

1

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; }

Sign up to request clarification or add additional context in comments.

2 Comments

@Jayden change Object.assign(...keys.map((k, i) to Object.assign({},...keys.map((k, i)
Would you know to concat a title variable which in the value contains all variant, producing {Size: '60cm', Color: 'White', Title: '60cm / White', Img: ''} ?
1

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)

2 Comments

What do I need to import for flatMap? Property 'flatMap' does not exist on type 'string[]'.
Typescript declaration file (.d.ts) doesn't have Array.prototype.flatMap. So, the compiler is complaining that flatMap is not an array extension Typescript flatMap, flat, flatten doesn't exist on type any[]
0

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.

2 Comments

Sorry I should have explained better, but size and color would be dynamic, so the model posted may differ to what the user is actually inputting.
You can still use this logic to generate variants, you just have to figure out a way to get the size and color or any other options.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.