Search code examples
jquery-uijquery-ui-draggable

Use clone helper only when button pressed


I am trying to make it so that my draggable element is only cloned when I press the Control button and drag it. My options for the draggable() function are:

var pressedKeys = {};
window.onkeyup = function(e) { pressedKeys[e.keyCode] = false; }
window.onkeydown = function(e) { pressedKeys[e.keyCode] = true; }

var draggable_options = {
    snap:       '.slot',
    snapMode:   'inner',
    scroll:     false,
    start:      function(event,ui){
        if (pressedKeys[17]){
            $(ui.helper).draggable('option','helper','clone');
        }
    },
}

Is this even possible? I've tried ui.element and also this and neither have worked. I'm not sure if you can change options at runtime for the jquery functions.


Solution

  • Consider the following.

    $(function() {
      var pressedKeys = {
        17: false
      };
      $(window).on({
        keyup: function(e) {
          pressedKeys[e.keyCode] = false;
          $("#draggable").draggable("option", "helper", "original");
        },
        keydown: function(e) {
          console.log("Key Pressed: " + e.keyCode);
          pressedKeys[e.keyCode] = true;
          $("#draggable").draggable("option", "helper", "clone");
        }
      })
      $("#draggable").draggable({
        snap: '.slot',
        snapMode: 'inner',
        scroll: false
      });
    });
    #draggable {
      width: 150px;
      height: 150px;
      padding: 0.5em;
    }
    <link rel="stylesheet" href="//code.jquery.com/ui/1.13.1/themes/base/jquery-ui.css">
    <script src="https://code.jquery.com/jquery-3.6.0.js"></script>
    <script src="https://code.jquery.com/ui/1.13.1/jquery-ui.js"></script>
    
    <div id="draggable" class="ui-widget-content">
      <p>Drag me around</p>
    </div>

    An alternative solution. I would advise this solution personally.

    $(function() {
      var pressedKeys = {
        17: false
      };
      $(window).on({
        keyup: function(e) {
          pressedKeys[e.keyCode] = false;
        },
        keydown: function(e) {
          console.log("Key Pressed: " + e.keyCode);
          pressedKeys[e.keyCode] = true;
        }
      })
      $("#draggable").draggable({
        snap: '.slot',
        snapMode: 'inner',
        scroll: false,
        helper: function() {
          return (pressedKeys[17] ? $(this).clone().removeAttr("id") : $(this));
        }
      });
    });
    #draggable, .ui-draggable {
      width: 150px;
      height: 150px;
      padding: 0.5em;
    }
    <link rel="stylesheet" href="//code.jquery.com/ui/1.13.1/themes/base/jquery-ui.css">
    <script src="https://code.jquery.com/jquery-3.6.0.js"></script>
    <script src="https://code.jquery.com/ui/1.13.1/jquery-ui.js"></script>
    
    <div id="draggable" class="ui-widget-content">
      <p>Drag me around</p>
    </div>

    See more: https://api.jqueryui.com/draggable/#option-helper

    The start callback is triggered too late to generate a Clone. This is why helper option offers a Function to dynamically create the the helper as needed.

    Here is the _createHelper code from the library:

    var o = this.options,
      helperIsFunction = typeof o.helper === "function",
      helper = helperIsFunction ? $( o.helper.apply( this.element[ 0 ], [ event ] ) ) : ( o.helper === "clone" ? this.element.clone().removeAttr( "id" ) : this.element );
    

    Simply perform a similar activity to replicate the code. Conditionally, it will return the original or a clone.