问题
I need to add "Select All" option in my multi-select. It should be displayed if there is at least 1 filtered option. Click on "Select All" should then add only filtered options (not all options necessarily) to already selected options.
- Input is empty, so all options are "filtered":
Clicking on Select All option would then add all options to selected options.
- Input contains "custom", so only one option remains::
Clicking on Select All option would then add only that one option to selected options.
It was easy to add "Select all" option that adds all initial options, but that isn't the solution to my problem. I managed to partially solve my problem by manually filtering options and storing them filtered in component's state, but I hope there is a simpler solution.
回答1:
I would use a combination of filterOption, InputChange and onChange props:
- In
InputChangeyou will catch theinputValueevery time the user changes it and store it into the state. This value will be reused inonChange. - You need to change the initial
filterOptionto display yourSelect allall the time. Original logic is ifinputValueisnullreturnstrueelse returnstrueisinputValueis included in option label or value. Before doing this logic, we had an other condition where if option value corresponds to yourSelect alloption then returnstrueright away. - In
onChange; by default the returned options are those received. Then if an option has been selected (as it's multiple it could be removed) and this option isSelect all, your returned value should be a copy of all the options and filter them by theinputValue.
Maybe there's a simplest way to do it but I think this one it pretty effective:
onChange = (opt, { option }) => {
let newOpts = opt;
let string = this.state.searchField;
if (option && option.value === "all") {
let filteredOptions = clone(options);
filteredOptions = filteredOptions.filter(
filteredOption =>
isIncludingString(string, filteredOption) &&
!newOpts.includes(filteredOption)
);
string = null;
newOpts = newOpts
.concat(filteredOptions)
.filter(newOpt => newOpt.value !== "all");
}
this.setState({
searchField: string,
values: newOpts
});
};
onInputChange = (string, { action }) => {
if (action === "input-change") {
this.setState({
searchField: string
});
}
};
filterOption = ({ label, value }, string) => {
if (value === "all") {
return true;
} else if (string) {
return label.includes(string) || value.toString().includes(string);
} else {
return true;
}
};
Important note, in my example I use
clonefromlodash
Below the isIncludingString function used in onChange.
function isIncludingString(string, option) {
let result = false;
if (
!string ||
option.label.toString().includes(string) ||
option.value.toString().includes(string)
) {
result = true;
}
return result;
}
Here a live example.
来源:https://stackoverflow.com/questions/57698868/react-select-ismulti-select-all-filtered-options