0

I'm trying to get dragItem_1 to only be accepted by target_1 and so on.

I'd like to dynamically change the accept parameter to whatever the id of the item being dragged is.

I can get it to work by defining each draggable and droppable item, but since the amount of items and targets are user generated I need to do it dynamically.

$( function() {
  $( ".js-draggable-box" ).draggable({
    revert: "invalid",
    start: function( event, ui ) {
      var item = ui.draggable;
      var id = $(item).attr('id');
      console.log(id)
    }
  });

  $( ".js-drop-target" ).droppable({
    accept: ".js-draggable-box",
    drop: function( event, ui ) {
      var dropped = ui.draggable;
      var droppedOn = $(this);
      $(this).addClass( "c-drop-target--correct" ).droppable("disable");
      $(dropped).detach().css({top: 0,left: 0}).appendTo(droppedOn).draggable("disable");
    }
  });
} );

I've also tried to get the ID on the start event but I get an undefined.

Kara
  • 6,115
  • 16
  • 50
  • 57
jkoler
  • 66
  • 1
  • 3
  • This will be done in `start`, but how does each drag-item know which target? Or are you saying you want each target to no longer be droppable when an item is dropped in it? IT is not clear what you are trying to accomplish. – Twisty Aug 05 '17 at 15:57

3 Answers3

0

It's not clear on what you want to accomplish. That said, there is a way to update the accept option of a droppable when you begin to drag an item.

I will show you two methods that work.

First, initial drop items. Then the drag items. This ensures that we can update the drop options when we start our drag.

$(function() {
  $(".drop_items .box").droppable({
    accept: ".none",
    drop: function(event, ui) {
      var dropped = ui.draggable;
      var droppedOn = $(this);
      $(this).addClass("c-drop-target--correct").droppable("disable");
      dropped.detach().css({
        top: 0,
        left: 0
      }).appendTo(droppedOn).draggable("disable");
    }
  });

  $(".drag_items .box").draggable({
    revert: "invalid",
    start: function(e, ui) {
      var item = ui.helper.attr("id")
      var target = "#dropTarget_" + item.slice(-1);
      console.log("Setting 'accept' for " + target + " to '#" + item + "'");
      $(target).droppable("option", "accept", "#" + item);
    }
  });
});

Working example: https://jsfiddle.net/Twisty/agypswbj/6/

Some things to note, draggable uses ui.helper, not ui.draggable. The ui.helper and ui.draggable are jQuery Objects and do not have to be wrapped with $().

Second, we can use our accept callback option in droppable.

$(function() {
  $(".drop_items .box").droppable({
    accept: function(item) {
      var target = $(this);
      var targetNumber = target.attr("id").slice(-1);
      var itemNumber = item.attr("id").slice(-1);
      return targetNumber === itemNumber;
    },
    drop: function(event, ui) {
      var dropped = ui.draggable;
      var droppedOn = $(this);
      $(this).addClass("c-drop-target--correct").droppable("disable");
      dropped.detach().css({
        top: 0,
        left: 0
      }).appendTo(droppedOn).draggable("disable");
    }
  });

  $(".drag_items .box").draggable({
    revert: "invalid"
  });
});

Working Example: https://jsfiddle.net/Twisty/agypswbj/5/

Hope that helps.

Twisty
  • 30,304
  • 2
  • 26
  • 45
0

The documentation for jQuery says that the accept option accepts both strings (like .js-draggable-box in your example) and functions. I believe an anonymous function should help.

accept

Type: Selector or Function()

Default: "*"

Controls which draggable elements are accepted by the droppable.

Multiple types supported:

Selector: A selector indicating which draggable elements are accepted.

Function: A function that will be called for each draggable on the page (passed as the first argument to the function). The function must return true if the draggable should be accepted.

Source: https://api.jqueryui.com/droppable/#option-accept

If you want an example, here's a StackOverflow question/answer about this: jquery droppable accept. Scroll down to morten.c's answer.

xfactorial
  • 161
  • 1
  • 8
-1

Hopefully I've understood you correctly, So on the assumption that you wanted targeted drop zones, then it's simply matching values/attributes and voiding the request if false.

Now my approach significantly changes what you have. I opted for Sortable

MVC/HTML

    @foreach (var item in Model.Items)
    {
      <div class="js-drag-container drag-container" data-item-id="@item.Id">
         <h3 class="ui-state-disabled">
          Item @item.Name <i class="fa fa-info-circle info-circle-icon" aria-hidden="true" data-make="@item.Make" data-model="@item.model" data-serial="@item.SerialNumber"></i>
                                <span>@item.something</span>
                                <span>@item.something</span>
        </h3>

         @foreach (var i in item.alias)
         {
          <div class="alias-item btn-red" data-item-id="@item.Id">
              <p class="alias">@i.Alias</p>
          </div>
          }
       </div>
    }

JS

It's a rather crude attempt, but applying a unique id and comparing on the receive, you can cancel the drop.

$(".js-drag-container").sortable({
    connectWith: ".js-drag-container",
    delay: 15,
    revert: true,
    dropOnEmpty: true,
    scroll: false,
    cursor: "move",
    items: "> div:not(.ui-state-disabled)",
    start: function (event, ui) {
    },
    stop: function (event, ui) {
    },
    receive: function (event, ui) {

        //Item being moved.
        var childId = ui.item.attr('data-item-id');
        //parentId of the col being dropped into
        var parentId = ui.item.parent().attr('data-item-id');

        if (childId != parentId)
        {
            //Cancel drop
            $(ui.sender).sortable('cancel');

            console.log("Drop Cancelled")
        }

    }
Tez Wingfield
  • 2,129
  • 5
  • 26
  • 46