-
-
Save sman591/e46cb24bdae64469b3a45b4f0116fb03 to your computer and use it in GitHub Desktop.
React wrapper around Selectize.js using ES6 and JSX
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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