-
-
Save superKalo/a7b1fa9d68fbae6cdbf66be7d0588937 to your computer and use it in GitHub Desktop.
class Sortable extends React.Component { | |
componentDidMount() { | |
// Every React component has a function that exposes the | |
// underlying DOM node that it is wrapping. We can use that | |
// DOM node, pass it to jQuery and initialize the plugin. | |
// You'll find that many jQuery plugins follow this same pattern | |
// and you'll be able to pass the component DOM node to jQuery | |
// and call the plugin function. | |
// Get the DOM node and store the jQuery element reference | |
this.$node = $(this.refs.sortable); | |
// Initialize the jQuery UI functionality you need | |
// in this case, the Sortable: https://jqueryui.com/sortable/ | |
this.$node.sortable({ | |
// Get the incoming `opacity` prop and use it in the plugin configuration | |
opacity: this.props.opacity, | |
// Get the incoming onChange func and we invoke it on the Sortable `change` event | |
change: (event, ui) => this.props.onChange(event, ui) | |
}); | |
} | |
// Force a single-render of the component, | |
// by returning false from shouldComponentUpdate ReactJS lifecycle hook. | |
// Right after ReactJS adds the element in the actual DOM, | |
// we need to pass the future control to jQuery. | |
// This way, ReactJS will never re-render our component, | |
// and jQuery will be responsible for all updates. | |
shouldComponentUpdate() { | |
return false; | |
} | |
componentWillReceiveProps(nextProps) { | |
// Each time when component receives new props, | |
// we should trigger refresh or perform anything else we need. | |
// For this example, we'll update only the enable/disable option, | |
// as soon as we receive a different value for this.props.enable | |
if (nextProps.enable !== this.props.enable) { | |
this.$node.sortable(nextProps.enable ? 'enable' : 'disable'); | |
} | |
} | |
// jQuery UI sortable expects a <ul> list with <li>s. | |
renderItems() { | |
return this.props.data.map( (item, i) => | |
<li key={i} className="ui-state-default"> | |
<span className="ui-icon ui-icon-arrowthick-2-n-s"></span> | |
{ item } | |
</li> | |
); | |
} | |
render() { | |
return ( | |
<ul ref="sortable"> | |
{ this.renderItems() } | |
</ul> | |
); | |
} | |
componentWillUnmount() { | |
// Clean up the mess when the component unmounts | |
this.$node.sortable('destroy'); | |
} | |
}; | |
// Optional: set the default props, in case none are passed | |
Sortable.defaultProps = { opacity: 1, enable: true }; | |
// Optional: set the prop types | |
Sortable.propTypes = { | |
opacity: React.PropTypes.number, | |
enable: React.PropTypes.bool, | |
onChange: React.PropTypes.func.isRequired | |
}; | |
export default Sortable; |
// And here's how to use the <Sortable /> component: | |
class MyComponent extends React.Component { | |
constructor(props) { | |
super(props); | |
// Use this flag to disable/enable the <Sortable /> | |
this.state = { isEnabled: true }; | |
this.toggleEnableability = this.toggleEnableability.bind(this); | |
} | |
toggleEnableability() { | |
this.setState({ isEnabled: ! this.state.isEnabled }); | |
} | |
handleOnChange(event, ui) { | |
// Attach any custom behavior here | |
console.log('DOM changed!', event, ui); | |
} | |
render() { | |
const list = ['ReactJS', 'JSX', 'JavaScript', 'jQuery', 'jQuery UI']; | |
return ( | |
<div> | |
<button type="button" | |
onClick={this.toggleEnableability}> | |
Toggle enable/disable | |
</button> | |
<Sortable | |
opacity={0.8} | |
data={list} | |
enable={this.state.isEnabled} | |
onChange={this.handleOnChange} /> | |
</div> | |
); | |
} | |
} | |
ReactDOM.render(<MyComponent />, document.getElementById('app')); |
Hi! how import jquery and jquery-ui in my component? I have a problem with this.
@superKalo Do you also have a solution for connected sortables? Drag and drop from a list to another.
This was extremely helpful for me, as I am migrating from a server-side rendered interface to React and didn't want to re-create my UI.
I did have an issue with:
this.$node.sortable('destroy');
I consistently got a Javascript error for this method.
My workaround was:
this.$node.remove()
I don't know if it's strictly necessary or even helpful.
@tarkancorak i love you so much man, I spent like 10 hours now trying to figure this import out
@tarkancorak love you too man, spent two hours trying to figure out the import. Finally worked!!!!
Hi
I used your solution for the Draggable component but following code returns an error:
Uncaught TypeError: _this4.props.onDrag is not a function
Can you help me?
`
class DragAndDrop extends Component {
constructor(props) {
super(props);
this.state = {
idImg: null,
idItem: null
};
this.handleOnDrag = this.handleOnDrag.bind(this);
this.handleOnDrop = this.handleOnDrop.bind(this);
}
render() {
return(
< img src="/images/1.jpg" id="img-1" className="img" onDrag={this.handleOnDrag} />
< div id="item-1" className="item" onDrop={this.handleOnDrop} > < /div>
)
}
handleOnDrag() {
this.setState({ idImg: $(this).attr("id") });
}
handleOnDrop() {
this.setState({ idItem: $(this).attr("id") });
}
componentDidMount() {
$(".img").draggable({
snap: ".item",
drag: (event, ui) => this.props.onDrag()
});
$(".item").droppable({
drop: (event, ui) => this.props.onDrop()
});
}
}
`
can you give an example on integrating to a funtional component also
@tarkancorak in the jsfidle, jquery and jqueryui are loaded in the global namespace like react is, so you do not need to import them because they are already available