2014-11-13 4 views
4

Я внимательно следил за реализацией Drag & Drop in Angular, который я нашел изначально в this StackOverflow answer, который ссылается на блог писателя и код GitHub.Как отправить функцию DOM в директиву в AngularJS?

Когда я реализовал его и протестировал его в моем проекте, я получил ошибку:

[$parse:isecdom] Referencing DOM nodes in Angular expressions is disallowed! Expression: dropped(dragEl, dropEl) 

According to Angular Docs, проблема в том, что я ссылку на функции, которая принимает объекты DOM в качестве параметров внутри DOM атрибутов - это что происходит в этой строке:

<div x-lvl-drop-target='true' x-on-drop='dropped(dragEl, dropEl)'>drop zone</div> 

Как вы можете видеть, атрибут on-drop проходит эту dropped функции (которая определена в моем контроллере, к директиве lvlDropTarget (размещен ниже), который называет его действием действия перетаскивания, которое делает пользователь. Мне нравится этот дизайн, так как он делает директиву многократной для множества различных возможностей перетаскивания в том же приложении. По сути, мне просто нужно определить другую функцию в моем контроллере и передать ее в директиву через атрибут on-drop.

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

Вот lvlDropTarget директивы

module.directive('lvlDropTarget', ['$rootScope', 'uuid', 
    function ($rootScope, uuid) { 
    return { 
     restrict: 'A', 
     scope: { 
     onDrop: '&' 
     }, 
     link: function (scope, el, attrs, controller) { 
     var id = angular.element(el).attr("id"); 
     if (!id) { 
      id = uuid.new() 
      angular.element(el).attr("id", id); 
     } 

     el.bind("dragover", function (e) { 
      if (e.preventDefault) { 
      e.preventDefault(); // Necessary. Allows us to drop. 
      } 

      if (e.stopPropagation) { 
      e.stopPropagation(); 
      } 

      e.dataTransfer.dropEffect = 'move'; 
      return false; 
     }); 

     el.bind("dragenter", function (e) { 
      angular.element(e.target).addClass('lvl-over'); 
     }); 

     el.bind("dragleave", function (e) { 
      angular.element(e.target).removeClass('lvl-over'); // this/e.target is previous target element. 
     }); 

     el.bind("drop", function (e) { 
      if (e.preventDefault) { 
      e.preventDefault(); // Necessary. Allows us to drop. 
      } 

      if (e.stopPropogation) { 
      e.stopPropogation(); // Necessary. Allows us to drop. 
      } 

      var data = e.dataTransfer.getData("text"); 
      var dest = document.getElementById(id); 
      var src = document.getElementById(data); 

      scope.onDrop({ 
      dragEl: src, 
      dropEl: dest 
      }); 
     }); 

     $rootScope.$on("LVL-DRAG-START", function() { 
      var el = document.getElementById(id); 
      angular.element(el).addClass("lvl-target"); 
     }); 

     $rootScope.$on("LVL-DRAG-END", function() { 
      var el = document.getElementById(id); 
      angular.element(el).removeClass("lvl-target"); 
      angular.element(el).removeClass("lvl-over"); 
     }); 
     } 
    } 
    } 
]); 
+0

Я начал щедрость, так как я не могу найти ответа в Интернете об этом. – Cleiton

+0

Вы тоже используете jQuery. Это может быть причиной ошибки. –

ответ

4

Вопрос был logged on github для этого 14 октября : Было предложено

AngularJS is now giving this error: "Referencing DOM nodes in Angular expressions is disallowed!", because of this: on-drop="controller.dropped(dragEl, dropEl)".

следующее решение:

Returning the DOM elements themselves causing an $parse:isecdom error in newer versions of AngularJS. Simply enough, let the dropped(...) callback handle fetching the elements.

suggested code change on github

Так что, если это изменение будет принято, то директива будет изменен, чтобы вернуть перетащены идентификаторами элементов. Затем он до обратного вызова, чтобы сделать document.getElementById:

$scope.dropped = function(dragId, dropId) { 
    var dragEl = document.getElementById(dragId); 
    var dropEl = document.getElementById(dropId); 

    console.log(dragEl, dropEl); 
} 

Сказав, что, Угловое добавил isecdom validation к их expression sandboxing уважительной причине:

AngularJS restricts access to DOM nodes from within expressions since it's a known way to execute arbitrary Javascript code.

This check is only performed on object index and function calls in Angular expressions. These are places that are harder for the developer to guard. Dotted member access (such as a.b.c) does not perform this check - it's up to the developer to not expose such sensitive and powerful objects directly on the scope chain.

To resolve this error, avoid access to DOM nodes.

Вместо того, чтобы пытаться обойти эту защиту, Я предпочитаю ваш выбор use ngDraggable - который поощряет использование declarative views и не требует DOM manipulation in your controller. Хороший звонок.

1

Я думаю, решение вашей проблемы достаточно просто - использовать промежуточный объект завернуть dragEl и dropEl, например, так:

в функции связи:

scope.onDrop({ 
     event : { 
      dragEl: src, 
      dropEl: dest 
     } 
     }); 

в html:

<div x-lvl-drop-target='true' x-on-drop='dropped(event)'>drop zone</div> 

в снаружи:

$scope.dropped = function(event){ 
    console.log('dropped', event); 
} 

И работая DEMO.


В качестве альтернативы вы можете сохранить информацию о событии перетаскивания в value, например, так:

app.value('dropEvent', {dropEl:null, dragEl:null}); 

app.directive('lvlDropTarget', 
    function ($rootScope, dropEvent) { 
    return { 

//... 

     link: function (scope, el, attrs, controller) { 

//... 

     el.bind("dragover", function (e) { 

//... 

      dropEvent.dragEl = src; 
      dropEvent.dropEl = dest; 

      scope.onDrop(); 
     }); 
//... 

    } 
    } 
); 

Затем, чтобы использовать его в контроллер/вне контекста:

app.controller('MainCtrl', function($scope, dropEvent) { 
    $scope.dropped = function(){ 
    console.log('dropped', dropEvent); 
    } 
}); 

DEMO

+0

Это отличные предложения. Я закончил использование 'ngDraggable' для перетаскивания, но информация в этом ответе по-прежнему ценна. Я оставляю это до Клейтона, чтобы решить, является ли это принятым ответом (если он наградит вас щедростью) – CodyBugstein