Reputation: 1025
I am trying to select a group of radio buttons on a page. Each of the inputs have the following:
<input type="radio" class="wc-pao-addon-field wc-pao-addon-radio" name="addon-761-soapbar-covers-0[]" data-raw-price="32" data-price="32" data-price-type="quantity_based" value="gold-soapbar-set" data-label="Gold Soapbar (Set)">
I can't select by the data attributes as they are shared with other inputs that I don't want to disable. So far, I can only grab the value
as the value changes from gold
to raw-nickel
to polished-nickel
to chrome
, etc.
What I have is the following:
//Initialize empty array
this.metalCovers = [];
//Grab all inputs
this.covers = Array.from(this.soapbarCovers.querySelectorAll("input"));
//Then filter them by their values and store in new variable
this.chromeCovers = this.covers.filter((cover) => cover.value.indexOf("chrome") !== -1);
this.blackCovers = this.covers.filter((cover) => cover.value.indexOf("matte") !== -1);
this.goldCovers = this.covers.filter((cover) => cover.value.indexOf("gold") !== -1);
this.nickelCovers = this.covers.filter((cover) => cover.value.indexOf("nickel") !== -1);
//Create new array from filtered inputs
this.metalCovers = [this.chromeCovers, this.blackCovers, this.goldCovers, this.nickelCovers];
//flatten the new array
this.metalCovers = [].concat.apply([], this.metalCovers);
So, this works, but I'm trying to discover a cleaner way to approach this code. I was thinking it would clean it up if I could Array.filter()
by multiple values, but nothing came up in my research.
Does anything stick out to you?
Upvotes: 0
Views: 65
Reputation: 11
Coming across with this one:
const filtered = Array.from(this.soapbarCovers.querySelectorAll("input"))
.filter(input => ['chrome', 'matte', 'gold', 'nickel'].includes(input.value));
Does pretty much what you need in just one line.
Example:
const metalCovers = [
{ attr: 'a1', value: 'chrome'},
{ attr: 'a2', value: 'matte'},
{ attr: 'a3', value: 'gold'},
{ attr: 'a4', value: 'nickel'},
{ attr: 'a5', value: 'chrome'},
{ attr: 'a6', value: 'silver'}, // should be left out
{ attr: 'a7', value: 'copper'}, // should be left out
{ attr: 'a8', value: 'gold'},
{ attr: 'a9', value: 'chrome'},
{ attr: 'a10', value: 'matte'},
{ attr: 'a11', value: 'nickel'},
];
const filtered = metalCovers.filter(input => ['chrome', 'matte', 'gold', 'nickel'].includes(input.value));
console.log(filtered);
will output this:
[
{ attr: 'a1', value: 'chrome' },
{ attr: 'a2', value: 'matte' },
{ attr: 'a3', value: 'gold' },
{ attr: 'a4', value: 'nickel' },
{ attr: 'a5', value: 'chrome' },
{ attr: 'a8', value: 'gold' },
{ attr: 'a9', value: 'chrome' },
{ attr: 'a10', value: 'matte' },
{ attr: 'a11', value: 'nickel' }
]
Upvotes: 0
Reputation: 195
//Initialize empty array
this.metalCovers = [];
//Grab all inputs
this.covers = Array.from(this.soapbarCovers.querySelectorAll("input"));
//Then filter them by their values and store in new variable
this.chromeCovers = [];
this.blackCovers = [];
this.goldCovers = [];
this.nickelCovers = [];
this.covers.forEach( cover => {
switch (cover.value) {
case "chrome": this.chromeCovers.push(cover); break;
case "matte": this.blackCovers.push(cover); break;
case "gold": this.goldCovers.push(cover); break;
case "raw-nickel":
case "polished-nickel":
this.nickelCovers.push(cover);
break;
default: console.error(`Invalid cover "${cover.value}"!`);
}
});
//Create new array from filtered inputs
this.metalCovers = [this.chromeCovers, this.blackCovers, this.goldCovers, this.nickelCovers];
//flatten the new array
this.metalCovers = [].concat.apply([], this.metalCovers);
Upvotes: 1
Reputation: 169407
I'd just do something like
// Define the keywords we're looking for in the value
const keywords = ["chrome", "matte", "gold", "nickel"];
// Grab all inputs
const inputs = Array.from(this.soapbarCovers.querySelectorAll("input"));
// Filter them...
this.metalCovers = inputs.filter((cover) =>
// If any of the keywords appears in the value,
// this is an input we care about
keywords.some((kw) => cover.value.includes(kw))
);
Or if you want to be really efficient and have the browser CSS engine do all the work,
this.metalCovers = Array.from(this.soapbarCovers.querySelectorAll("input[value*=chrome],input[value*=matte],input[value*=gold],input[value*=nickel]"));
which of course can be made more maintainable via
const keywords = ["chrome", "matte", "gold", "nickel"];
this.metalCovers = Array.from(this.soapbarCovers.querySelectorAll(keywords.map(k => `input[value*=${k}`]).join(','));
Upvotes: 2