Search code examples
javascriptjqueryjquery-uijquery-ui-draggablejquery-ui-droppable

jQuery UI Droppable with an item dropped by default (without changing the markup structure)


I'm using .draggable() and .droppable() to calculate the price of the items that were dropped in the container, based on the weight and a constant defining the per gram price of all items.

Now I'd like to have one of the items dropped within the container by default, together with the correct calculations and the possibility to drag more/less items over the container. The positioning should be like image 1 when the reset button is pressed and I must be able to drag the default item out of the container just like the other draggables.

This is what it looks like now: jQuery draggable

And this is how I want it to look like on page load: Droppable with default drop

I haven't found any documentation covering default droppables like this, so I don't really know where to start. I've prepared a Jsfiddle here: http://jsfiddle.net/gPFMk/ and a Jsbin for those who like it better http://jsbin.com/oxuguc/1/edit

var price = 0, math = '', items = [], state = 'outside', wprice = 209;


function calcPrice(math) {
  price = 0;
  weight = 0;
  $('.counter-number').remove();
  addticker(0);
  console.log("Item array: " + items);
  $.each( items, function( key, value ) {
    price+= parseInt($(".draggable[data-item='" + value + "']").attr('id'));
    weight+= $(".draggable[data-item='" + value + "']").data('weight');
    loadticker(price);
  });
  $('#weight').html('<span>weight </span>' + weight + ' g');
}

function revertDraggable($selector) {
  $selector.each(function() {
    var $this = $(this),
      position = $this.data("originalPosition");
      if (position) {
        $this.animate({
          left: position.left,
          top: position.top
        }, 500, function() {
          $this.data("originalPosition", null);
        });
      }
    items = [];
    $('#droppable').removeClass('active');
    $('.counter-number').remove();
    calcPrice();
  });
}

$(function() {
  $.each($('.draggable'), function() {
    var $this = $(this),
    weight = $this.data('weight');
    $this.attr('id', weight*wprice);
  });

  $(".draggable").draggable({
    revert: function (event, ui) {
      $(this).data("draggable").originalPosition = {
        top: 0,
        left: 0
      };
      return !event;
    },
    cursor: "move",
    cursorAt: {
      top: 56,
      left: 56
    },
    stack: "div",
    containment: "#container",
    scroll: false
  });

  $("#droppable").droppable({
    drop: function(e, u) {
      $(this).addClass('active');
      if ($.inArray(u.draggable.data('item'), items) == -1) {
        items.push(u.draggable.data('item'));
        price = 0;
        weight = 0;
        calcPrice('add');
        u.draggable.data('state', 'inside');
      }
      if (!u.draggable.data("originalPosition")) {
        u.draggable.data("originalPosition",
        u.draggable.data("draggable").originalPosition);
      }
    },
    over: function() {
      $(this).addClass('active');
    },
    out: function(e, u) {
      if(u.draggable.data('state') == 'inside') {
        u.draggable.data('state', 'outside');
        var itemIndex = $.inArray(u.draggable.data('item'), items);
        items.splice(itemIndex, 1);
        price = $("#droppable").text();
        calcPrice('remove');
      }
      if (items.length === 0)
        $('#droppable').removeClass('active');
    }
  });
  $('#container').on('click', '#reset', function() {
    revertDraggable($(".draggable"));
  });
});

 

  <div id="container">
    <div id="heft">
      <div id="info">
          <div id="price">
            <span>price</span>
            <div class="counter-wrap">
              <div class="counter-number">
                  &nbsp;
              </div>
            </div>€
          </div>
          <div id="weight">
            <span>weight</span>
            0 g
          </div>
          <button id="reset">Reset</button>
        </div>
        <div id="droppable"></div>
      </div>
      <div id="items">
      <div class="draggable" data-item="3" data-weight="15" data-state="outside"><img src="http://wemakeawesomesh.it/nyancat/nyan.gif" width="90" height="90"></div>
      <div class="draggable" data-item="2" data-weight="35" data-state="outside"><img src="http://wemakeawesomesh.it/nyancat/nyan.gif" width="90" height="90"></div>
      <div class="draggable" data-item="1" data-weight="8" data-state="outside"><img src="http://wemakeawesomesh.it/nyancat/nyan.gif" width="90" height="90"></div>
      </div>
    </div>

If I move the code of one item to the droppable div like suggested, revertDraggable() and revert: won't work as expected.


Solution

  • Here's a solution that simulates an item drop for the first item on document load. The difficulty was to mimic what happens during a drop:

    $(".draggable[data-item='1']").attr(
        "style",
        "position: relative; z-index: 10; left: 300px; top: 30px"
    );
    
    var onDrop = function(e,u) {
        if ($.inArray(u.draggable.data('item'), items) == -1) {
            items.push(u.draggable.data('item'));
            price = 0;
            weight = 0;
            calcPrice('add');
            u.draggable.data('state', 'inside');
        }
        if (!u.draggable.data("originalPosition")) {
            u.draggable.data("originalPosition",
            u.draggable.data("draggable").originalPosition);
        }
    };
    
    onDrop.call($("#droppable"),
        {},{ draggable: $(".draggable[data-item='1']") }
    );
    

    Here is the link to the jsfiddle.