简体   繁体   中英

AngularJS Drag and Drop between lists breaks with 1.2

I've been using an implementation of this Drag and Drop with AngularJS and jQuery UI:

http://www.smartjava.org/examples/dnd/double.html

With AngularJS 1.0.8 it works flawlessly. With 1.2.11, it doesn't.

When using AngularJS 1.2 and dragging an item from the left list to the right one the model for the destination list updates correctly. However the DOM doesn't update correctly. Here is the directive that's being used from the example:

app.directive('dndBetweenList', function($parse) {

  return function(scope, element, attrs) {

    // contains the args for this component
    var args = attrs.dndBetweenList.split(',');
    // contains the args for the target
    var targetArgs = $('#'+args[1]).attr('dnd-between-list').split(',');

    // variables used for dnd
    var toUpdate;
    var target;
    var startIndex = -1;

    // watch the model, so we always know what element
    // is at a specific position
    scope.$watch(args[0], function(value) {
        toUpdate = value;
    },true);

    // also watch for changes in the target list
    scope.$watch(targetArgs[0], function(value) {
        target = value;
    },true);

    // use jquery to make the element sortable (dnd). This is called
    // when the element is rendered
    $(element[0]).sortable({
        items:'li',
        start:function (event, ui) {
            // on start we define where the item is dragged from
            startIndex = ($(ui.item).index());
        },
        stop:function (event, ui) {
            var newParent = ui.item[0].parentNode.id;

            // on stop we determine the new index of the
            // item and store it there
            var newIndex = ($(ui.item).index());
            var toMove = toUpdate[startIndex];

            // we need to remove him from the configured model
            toUpdate.splice(startIndex,1);

            if (newParent == args[1]) {
                // and add it to the linked list
                target.splice(newIndex,0,toMove);
            }  else {
                toUpdate.splice(newIndex,0,toMove);
            }

            // we move items in the array, if we want
            // to trigger an update in angular use $apply()
            // since we're outside angulars lifecycle
            scope.$apply(targetArgs[0]);
            scope.$apply(args[0]);
        },
        connectWith:'#'+args[1]
    })
  }
});

Does something need to be updated for this to work properly with Angular 1.2? I feel like it has something to do with the scope.$apply but am not sure.

I see this is an older question, but I recently ran into the exact same issue with the Drag and Drop example. I don't know what has changed between angular 1.0.8 and 1.2, but it appears to be the digest cycle that causes problems with the DOM. scope.$apply will trigger a digest cycle, but scope.$apply in and of itself is not the issue. Anything that causes a cycle can cause the DOM t get out of sync with the model.

I was able to find a solution to the the problem using the ui.sortable directive. The specific branch that I used is here: https://github.com/angular-ui/ui-sortable/tree/angular1.2 . I have not tested with other branches.

You can view a working example here:

http://plnkr.co/edit/atoDX2TqZT654dEicqeS?p=preview

Using the ui-sortable solution, the 'dndBetweenList' directive gets replaced with the ui-sortable directive. Then there are a few changes to make.

In the HTML

<div class="row">
<div class="span4 offset2">
      <ul ui-sortable="sortableOptions" ng-model="source" id="sourceList"  ng-class="{'minimalList':sourceEmpty()}" class="connector">
        <li class="alert alert-danger nomargin" ng-repeat="item in source">{{item.value}}</li>
      </ul>
    </div>
<div class="span4">
      <ul ui-sortable="sortableOptions" id="targetList" ng-model="model" ng-class="{'minimalList':sourceEmpty()}" class="connector">
        <li class="alert alert-info nomargin" ng-repeat="item in model">{{item.value}}</li>
      </ul>
    </div>
  </div>

Note the dnd-between-list directive is no longer needed and is replaced with the ui-sortable.

In the module inject the ui-sortable, and in the controller specify that sortable options. The sortable accepts the same options as the jquery sortable.

app.js

var app = angular.module('dnd', ['ui.sortable']); 

ctrl-dnd.js

$scope.sortableOptions  = {
    connectWith: '.connector'
}

Only the additions to the controller are shown. Note that I added a .connector class on the ul. In the sortable I use .connector for the connectWith option.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM