Search code examples
reactjsdraggablereact-motion

How to clone a react element for dragging purposes


So, I have a list, and I can now drag elements (divs) out of that list, using react-draggable. React-draggable makes the original element draggable (makes sense), but I need to drag a copy (clone) of the original element, and keep the original element in place. So, I have the entities list that contain the elements, each element has an event that calls the parent element list hoping to clone the original shift, and wrap the original element with a draggable element in order to make it draggable. Once it it draggable/created, I want to attach it to a different element on the screen, and put the initial position to centre where the mouse cursor is. One last thing I want to do is that if the element is dropped in a "wrong" location, it should animate (react-motion I guess) a return to the original position. Originally it was written in Jquery and I obviously know how to use jquery-ui to make all this happen, but I'm a bit stuck with doing it the react way.

   var Scheduler = require('scheduler/components/Scheduler');

    var ShiftTypeDiv = require('scheduler/components/ShiftType');

    var Draggable = ReactDraggable;

    var ShiftTypes = React.createClass({
      getInitialState: function() {
         return ({
          shiftTypes: SchedulerStore.getShiftTypes(),
          clonedItem: null
         })
      },
      handleStart: function (event, ui) {
        console.log('handleStart: ', event);
        console.log('Position: ', ui.position);
      },

      cloneShiftBeforeDrag: function (item) {
        console.log('cloning', item);
        React.cloneElement(item);
        ReactDOM.findDOMNode
        this.setState({
          clonedItem: item
        });
      },

      handleDrag: function (event, ui) {
        console.log('handledrag: ',ui);
        console.log('dragging');
      },

      handleStop: function (event, ui) {
        console.log('handleStop: ', event);
        console.log('Position: ', ui.position);
      },

      render: function() {

        var self = this;

        shiftTypesJSX = this.state.shiftTypes.map(function(shiftType,index) {
        return (
                <ShiftTypeDiv shiftType={shiftType} key={index} cloneShiftBeforeDrag={self.cloneShiftBeforeDrag.bind(null, shiftType)} />
                )
        });

        return (
          <div >
             <div className="box-header">
              <ul>
                <li className="title title-name">Shift Templates</li>
                <li className="title edit-link"></li>
              </ul>
            </div>
              <div className="box-content" data-onboarding-item="2">
                <Draggable
                  handle=".ui-draggable"
                  zIndex={100}
                  onStart={this.handleStart}
                  onDrag={this.handleDrag}
                  onStop={this.handleStop}
                  >
                  <div className="draggable-custom-shift ui-draggable ui-draggable-handle"><strong>New Shift</strong></div>
                </Draggable>
              </div>
            <div className="box-content" id="shift-templates">
              <div className="row-fluid">
                <div id="shift-types-list" className="span12">
                  <div className="input-group shift-type-filter-form">
                    <input type="text" className="span12" id="shift-type-filter" placeholder="Filter shift templates" />
                    <i className="icon-remove-sign" id="remove-shift-type-filter"></i>
                  </div>
                  <div id="shift_types" >
                    {shiftTypesJSX}
                  </div>
                </div>
              </div>
            </div>
          </div>
          )
      }
    })

    module.exports = ShiftTypes;


var Scheduler = require('scheduler/components/Scheduler').default;

var Draggable = ReactDraggable;

var ShiftTypeDiv = React.createClass({
  handleStart: function (event, ui) {
    console.log('cloning');
    this.props.cloneShiftBeforeDrag(this);
  },

  handleDrag: function (event, ui) {
    console.log('handledrag: ',ui);
    console.log('dragging');
  },

  handleStop: function (event, ui) {
    console.log('handleStop: ', event);
    console.log('Position: ', ui);
    this.setState({

    })

  },
  render: function() {
    shiftType = this.props.shiftType;
    return (
      <Draggable
              bounds="body"
              zIndex={100}
              onStart={this.handleStart}
              onDrag={this.handleDrag}
              onStop={this.handleStop}
              position={null}
              >
        <div className="draggable-shift-type ui-draggable ui-draggable-handle" data-shift-type-id={shiftType.id}>
          {shiftType.name} <span dangerouslySetInnerHTML={{__html:shiftType.start_time + '-' + shiftType.end_time}}></span>
        </div>
      </Draggable>
      )
  }
})

module.exports = ShiftTypeDiv;

Solution

  • Since no one answered it, this was my solution. When the component identifies it's being dragged (prop dragged = true for example) it will just add another similar shift. I still didn't try to implement all the "animation" parts of it, but can either use css, or maybe react-motion.