skip to Main Content

I’m working on a headless Shopify store using Gatsby, and am having some trouble building a robust product option picker.

I have an options object that looks like this:

{
  extras: "Pouch only",
}

The key and value will be different for every product, so I won’t know the values.

I have a variants array that will have a key/value pair that matches this object. Here is the shape of the variants array:

[
  {
    extras: "Pouch only",
    ...otherValues,
  },
  {
    extras: "Add tassel",
    ...otherValues,
  },
  {
    extras: "Add charm",
    ...otherValues,
  },
  {
    extras: "Add tassel & charm",
    ...otherValues,
  },
  {
    sizes: "S",
    ...otherValues,
  },
  {
    sizes: "M",
    ...otherValues,
  },
  {
    sizes: "L",
    ...otherValues,
  },
  {
    sizes: "XL",
    ...otherValues,
  },
];

If I knew the name of the variant ahead of time, I could do something like this:

const newVariant = variants.find((v) => {
  return v.extras === options.extras;
});

How can I do the same thing without knowing the name of the key?

4

Answers


  1. Using Object.entries you can retrieve key/value pairs of the object, and check if .some(or .every depending on your needs) match:

    const newVariant = variants.find((v) => Object.entries(options).some(([key, value]) => v[key] === value));
    
    Login or Signup to reply.
  2. Take the entries of the option object and stringify them. Then, when searching through the variants, find (or filter) by the ones which have an entry matching the entry previously stringified:

    const optionsEntryVariants = Object.entries(options).map(JSON.stringify);
    const matchingVariants = variants.filter(
      variant => Object.entries(variant).some(
        entry => optionsEntryVariants.includes(JSON.stringify(entry))
      )
    );
    
    const options = {
      extras: "Pouch only",
    };
    
    const optionsEntryVariants = Object.entries(options).map(JSON.stringify);
    
    const variants = [
      {
        extras: "Pouch only",
        someOtherProp: 'someOtherVal',
      },
      {
        extras: "Add tassel",
        someOtherProp: 'someOtherVal',
      },
      {
        extras: "Add charm",
        someOtherProp: 'someOtherVal',
      },
      {
        extras: "Add tassel & charm",
        someOtherProp: 'someOtherVal',
      },
      {
        sizes: "S",
        someOtherProp: 'someOtherVal',
      },
      {
        sizes: "M",
        someOtherProp: 'someOtherVal',
      },
      {
        sizes: "L",
        someOtherProp: 'someOtherVal',
      },
      {
        sizes: "XL",
        someOtherProp: 'someOtherVal',
      },
    ];
    
    const matchingVariants = variants.filter(
      variant => Object.entries(variant).some(
        entry => optionsEntryVariants.includes(JSON.stringify(entry))
      )
    );
    
    console.log(matchingVariants);

    If you need every key-value pair in the options object to match, rather than just at least one to match, then change the .some to .every.

    You could make the function a bit more efficient by making a Set of the stringified entries instead of using an array:

    const optionsEntryVariants = new Set(
      Object.entries(options).map(JSON.stringify)
    );
    const matchingVariants = variants.filter(
      variant => Object.entries(variant).some(
        entry => optionsEntryVariants.has(JSON.stringify(entry))
      )
    );
    
    Login or Signup to reply.
  3. You can loop through the object key for check. I think this solves your issue.

    const options = {
        extras: "Pouch only",
    };
    
    const otherValues = {};
    
    const variants = [
        {
            extras: "Pouch only",
            ...otherValues,
        },
        {
            extras: "Add tassel",
            ...otherValues,
        },
        {
            extras: "Add charm",
            ...otherValues,
        },
        {
            extras: "Add tassel & charm",
            ...otherValues,
        },
        {
            sizes: "S",
            ...otherValues,
        },
        {
            sizes: "M",
            ...otherValues,
        },
        {
            sizes: "L",
            ...otherValues,
        },
        {
            sizes: "XL",
            ...otherValues,
        },
    ];
    
    let optionsKey = '';
    for (const opKey in options) {
        optionsKey = opKey
    }
    
    const newVariant = variants.find((v) => {
        for (const vKey in v) {
            if (vKey === optionsKey) {
                return v[vKey] === options[optionsKey];
            }
        }
    });
    Login or Signup to reply.
  4. You can do this using filter and then some inside of it. Here is how:

    var data = data = [ { extras: "Pouch only" }, { extras: "Add tassel",size : 'SomeFilter' }, { extras: "Add charm" }, { extras: "Add tassel & charm", }, { sizes: "S" }, { sizes: "M", }, { sizes: "L" }, { sizes: "XL" }];
    
    filter = { extras: "Pouch only" }
    
    var objectToFilter = Object.entries(filter);
    
    result1 = data.filter(val=>objectToFilter.some(([k,v])=>val.hasOwnProperty(k) && val[k].includes(v)));
    
    filter = { extras: "Pouch only", size : 'SomeFilter'};
    
    var objectToFilter = Object.entries(filter);
    
    result2 = data.filter(val=>objectToFilter.some(([k,v])=>val.hasOwnProperty(k) && val[k].includes(v)));
    
    console.log(result2);

    Also if you want search for all values in filter, some could be replaced with every method.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search