Skip to content

Instantly share code, notes, and snippets.

@sman591
Forked from heyimalex/Selectize.jsx
Last active August 22, 2017 21:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sman591/e46cb24bdae64469b3a45b4f0116fb03 to your computer and use it in GitHub Desktop.
Save sman591/e46cb24bdae64469b3a45b4f0116fb03 to your computer and use it in GitHub Desktop.
React wrapper around Selectize.js using ES6 and JSX
import React, { Component } from 'react';
// Wrapper around the selectize jQuery plugin.
export default class Selectize extends Component {
shouldComponentUpdate(nextProps) {
const self = this;
const shouldUpdate = Object.keys(nextProps).some(function(propName) {
// If it's handled, we'll deal with it on our own.
if (propName in handledProps) return false;
return nextProps[propName] !== self.props[propName];
});
if (shouldUpdate) return true;
this._updating = true;
// Handle our handledProps if they've changed.
// If they're not here, they probably need no handling.
if (nextProps.disabled !== this.props.disabled) {
if (nextProps.disabled) {
this.selectize.disable();
} else {
this.selectize.enable();
}
}
if (nextProps.placeholder !== this.props.placeholder) {
this.selectize.settings.placeholder = nextProps.placeholder;
this.selectize.updatePlaceholder();
}
if (nextProps.options !== this.props.options &&
!identicalArray(this.props.options, nextProps.options)) {
// Synchronously update the options, as
// Selectize's async load function causes
// issues.
this.selectize.clearOptions();
nextProps.options.forEach(function(option) {
self.selectize.addOption(option);
});
this.selectize.refreshOptions(false);
this.selectize.setValue(nextProps.value);
} else if (nextProps.value !== this.props.value) {
if (nextProps.multiple && nextProps.value !== null) {
if (!identicalArray(nextProps.value, this.getValue())) {
this.selectize.setValue(nextProps.value);
}
} else if (nextProps.value !== this.getValue()) {
this.selectize.setValue(nextProps.value);
}
}
this._updating = false;
return false;
}
componentDidMount() {
this.create();
}
componentWillUnmount() {
this.destroy();
}
componentWillUpdate() {
this.destroy();
}
componentDidUpdate() {
this.create();
}
getValue() {
return this.selectize.getValue();
}
create() {
const self = this;
const options = {};
selectizeOptNames.forEach(function(optName) {
if (optName in self.props) {
options[optName] = self.props[optName];
}
});
this.selectize = (
$(this.selectInput)
.selectize(options)
)[0].selectize;
this.selectize.setValue(this.props.value);
this.props.refSelectize && this.props.refSelectize(this.selectize);
this.selectize.on('change', this.handleChange.bind(this));
// Don't open the dropdown menu after removing an item
// https://github.com/selectize/selectize.js/issues/934
this.selectize.on('item_remove', function() {
if (!this.settings.closeAfterSelect) {
return;
}
this.$dropdown.css('opacity', '0');
const that = this;
setTimeout(function() {
self.selectize.close();
that.$dropdown.css('opacity', '1');
}, 100);
});
}
destroy() {
this.selectize.destroy();
}
handleChange(value) {
// Because handleChange often triggers state
// changes in containing components, we need to
// make sure that we're not currently updating from
// within another state change (otherwise react
// will throw an InvariantError).
if (!this._updating) {
this.props.handleChange(value);
}
}
render() {
return (
<select
className={this.props.className}
disabled={this.props.disabled}
multiple={this.props.multiple}
ref={(input) => { this.selectInput = input; }}
/>
);
}
}
Selectize.propTypes = {
className: React.PropTypes.string,
disabled: React.PropTypes.bool,
handleChange: React.PropTypes.func,
multiple: React.PropTypes.bool,
options: React.PropTypes.array,
placeholder: React.PropTypes.string,
refSelectize: React.PropTypes.func,
value: React.PropTypes.oneOfType([
React.PropTypes.string,
React.PropTypes.array,
]),
};
Selectize.defaultProps = {
value: '',
handleChange: $.noop,
};
function identicalArray(a1, a2) {
return (
a1.length === a2.length &&
!a1.some(function(e, idx) { return a2[idx] !== e; })
);
}
// -- unsupported props --
// autofocus: false,
// form: null,
// name: null
// required: false
// size: 0
const selectizeOptNames = [
'delimiter',
'diacritics',
'closeAfterSelect',
'create',
'createOnBlur',
'createFilter',
'highlight',
'persist',
'openOnFocus',
'maxOptions',
'maxItems',
'hideSelected',
'scrollDuration',
'loadThrottle',
'preload',
'dropdownParent',
'addPrecedence',
'selectOnTab',
'options',
'dataAttr',
'valueField',
'optgroupValueField',
'labelField',
'optgroupLabelField',
'optgroupField',
'sortField',
'searchField',
'searchConjunction',
'optgroups',
'optgroupOrder',
'load',
'score',
'render',
'plugins',
// Unofficial, but works as expected.
'placeholder',
];
var handledProps = {
value: true,
disabled: true,
placeholder: true,
handleChange: true,
options: true,
refSelectize: true,
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment