-
-
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')); |
@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
Hi! how import jquery and jquery-ui in my component? I have a problem with this.