Skip to content

Instantly share code, notes, and snippets.

@bobpace
Last active August 29, 2015 14:17
Show Gist options
  • Save bobpace/a5c28a1da4f0b4308780 to your computer and use it in GitHub Desktop.
Save bobpace/a5c28a1da4f0b4308780 to your computer and use it in GitHub Desktop.
React MultiSelect with item filter
var React = require('react');
var Input = require('react-bootstrap/src/Input');
var DropdownButton = require('react-bootstrap/src/DropdownButton');
var _ = require('lodash');
var escape = /[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g;
function escapeRegExp(str) {
return str.replace(escape, "\\$&");
};
var ListItemCheckbox = React.createClass({
getDefaultProps() {
return {
text: '',
onChange: _.noop
};
},
render() {
var checkboxProps = {};
if (this.props.checked !== undefined) {
checkboxProps.checked = this.props.checked
}
return (
<li className="checkbox">
<label>
<input type="checkbox" onChange={this.props.onChange} {...checkboxProps} />
<span>{this.props.text}</span>
</label>
</li>
);
}
});
var MultiSelect = React.createClass({
getDefaultProps() {
return {
items: [],
placeholder: 'Enter some filter text',
onChange: _.noop,
onItemSelected: _.noop,
onItemDeselected: _.noop
};
},
getInitialState() {
return {
selections: [],
filter: ''
};
},
handleItemClick(item) {
this.setSelected(item, !_.contains(this.state.selections, item.id));
},
handleFilterChange(event) {
// Keep track of every change to the filter input
this.setState({ filter: event.target.value });
},
createItem(item) {
var regex = new RegExp(escapeRegExp(this.state.filter), 'i');
var text = item.text || item.name || item.id;
return regex.test(text) ? (
<ListItemCheckbox
key={item.id}
text={text}
onChange={this.handleItemClick.bind(this, item)}
checked={_.contains(this.state.selections, item.id)}
/>
) : null;
},
setSelected(items, selected) {
// Accept an array or a single item
if (!(items instanceof Array)) {
items = [items];
}
var selections = this.state.selections;
var update = selected ? function(x) {
selections.push(x.id);
} : function(x) {
_.pull(selections, x.id);
};
items.forEach(update);
this.setState({selections: selections});
this.props.onChange(selections);
},
toggleSelectAll(event) {
this.setSelected(this.props.items, event.target.checked);
},
render() {
var totalSelected = this.state.selections.length;
var title = totalSelected ? totalSelected + " selected" : "--";
var selectAll = _.isEmpty(this.state.filter) ? (
<ListItemCheckbox text="Select All" onChange={this.toggleSelectAll} />
) : null;
return (
<div className="multiselect">
<DropdownButton title={title}>
<li>
<input
type="text"
onChange={this.handleFilterChange}
value={this.state.filter}
placeholder={this.props.placeholder}
/>
</li>
{selectAll}
<ul>{this.props.items.map(this.createItem)}</ul>
</DropdownButton>
</div>
)
}
})
module.exports = MultiSelect;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment