Перетащите объект в отсортированный список - AngularJS

Проблема:

Я пытаюсь воссоздать функциональность Draggable + Sortable из jQuery и не могу заставить упавший элемент войти в мой массив объектов.

Я хочу, чтобы перетащить $.draggable() кнопки в $.sortable() список. Я хочу, чтобы кнопка представляла объект со свойствами (это может быть ассоциативный массив или сам объект), и когда я удаляю его в своем списке, я хочу, чтобы он помещал себя в массив в той позиции, в которой он был удален.


Просто чтобы прояснить, у меня есть массив потенциальных объектов в меню слева. Справа я использую $http для вызова своего API для получения формы, в которой все поля хранятся в $scope. Я хочу, чтобы этот потенциальный объект (например, textarea) был сброшен в поля формы в позиции, где он был удален.

Бит jquery прост, но проблема заключается в несуществующем объекте в позиции в массиве $scope.


Что я пробовал:

Я был близок к смешиванию, комбинируя ui-sortable и $.draggable оболочку директивы, но мой код работает не очень хорошо.


Примеры:


Обновление 1:

Я добился прогресса с помощью ui-sortable по пользовательскому ui-sortable директивы в сочетании с директивой, которая оборачивает $.draggable(), $.draggable() уродливо, но работает.

Обновление 2:

У меня это работает сейчас, но я беру индекс из jquery и использую PHP, чтобы разрезать его в эту позицию, а затем перезагружаю весь список. Разговор о хромом должен быть лучше.

Обновление 3:

Вот рабочий пример модульного приложения для любого пользователя.

Ответы

Ответ 1

Нет angular -magic, который может помочь вам найти позицию нового или перемещенного элемента, но это легко сделать с jQuery. Я создал пример jQueryUI-demo wrapping, сортируемый и перетаскиваемый в директивах:

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

<ul>
  <li my-draggable="#sortable" class="ui-state-highlight">Drag me down</li>
</ul>

<ul my-sortable id="sortable">
  <li class="ui-state-default" ng-repeat="item in items">{{item.name}}</li>
</ul>

Значение my my-draggable - это идентификатор соответствующего элемента my-sortable. my-draggable в противном случае довольно прямо:

app.directive('myDraggable',function(){

  return {
    link:function(scope,el,attrs){
      el.draggable({
        connectToSortable: attrs.myDraggable,
        helper: "clone",
        revert: "invalid"
    });
    el.disableSelection();
    }
  }
})

В my-sortable Я слушаю событие deactivate, которое указывает, что элемент был удален. from - это позиция элемента в массиве, который является источником ng-repeat. ng-repeat создает дочернюю область для каждого элемента с переменной $index, указывающей положение текущего элемента в массиве. Если $index undefined, я знаю, что это новый элемент (может быть, лучший способ определить это, но он работает для этого примера). to - новое положение элемента. я $выдает событие "my-sorted", если был перемещен существующий элемент или событие "my-created", если новый элемент был добавлен.

app.directive('mySortable',function(){
  return {
    link:function(scope,el,attrs){
      el.sortable({
        revert: true
      });
      el.disableSelection();

      el.on( "sortdeactivate", function( event, ui ) { 
        var from = angular.element(ui.item).scope().$index;
        var to = el.children().index(ui.item);
        if(to>=0){
          scope.$apply(function(){
            if(from>=0){
              scope.$emit('my-sorted', {from:from,to:to});
            }else{
              scope.$emit('my-created', {to:to, name:ui.item.text()});
              ui.item.remove();
            }
          })
        }
      } );
    }
  }
})

В контроллере я создаю массив items и выслушиваю события:

$scope.items = [
  {name:'Item 1'},
  {name:'Item 2'},
  {name:'Item 3'},
  {name:'Item 4'},
];

$scope.$on('my-sorted',function(ev,val){
  // rearrange $scope.items
  $scope.items.splice(val.to, 0, $scope.items.splice(val.from, 1)[0]);
})

$scope.$on('my-created',function(ev,val){
  // create new item at position 
  $scope.items.splice(val.to, 0,
    {name:'#'+($scope.items.length+1)+': '+val.name});
})

Как вы можете видеть, когда вы добавляете или перемещаете элемент, модель в области становится обновленной.

Эти директивы не очень общие - вам, возможно, придется выполнить некоторую настройку, чтобы заставить их работать с вашим приложением.

Ответ 2

Вы должны иметь возможность делать все, что вам нужно, в вашей функции ссылок.

myapp.directive("menuDrag", function () {

    return{
        restrict: "A",
        link:     function (scope, element, attrs) {
            var item = $(".draggable").draggable(
                {
                    snap:   true,
                    revert: false,
                    // scope:".dropable"
                    //scope: "tasks"
                }
            )
            var target = $(".dropable").droppable({

                greedy:     true,
                hoverClass: "warning",
                accept:     ".draggable"
            })


            item.on("drag", function (evt) {
                item.css = ('background-color', 'red');
                //evt.stopPropagation();
                //evt.preventDefault();
            })


            target.on("over", function (evt) {

                target.css('background-color', 'blue')

                return false;
            });
            target.on("out", function (evt) {
                dropBox.css('background_color', 'red');


                return false;
            });
            target.on("drop", function (evt) {
                alert("Droped");
                return false;
            });
            //dragEnterLeave(evt);
        }
    }
})