2014-11-13 4 views
4

드래그 & Drop in Angular 구현에 대한 훌륭한 자습서를 따라 갔는데 원래는 this StackOverflow answer이라는 작가의 블로그와 GitHub 코드에 링크되어 있습니다. 나는 그것을 구현하고 내 프로젝트에서 그것을 시험 할 때AngularJS의 지시어에 DOM 함수를 보내는 방법은 무엇입니까?

, 나는 오류 가지고 :

[$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 속성이 지침 lvlDropTarget에, 내 컨트롤러에 정의되어이 dropped 기능 (통과 (아래 게시)는 사용자가 만든 드래그 앤 드롭 동작을 수행하도록 호출합니다. 이 디자인은 같은 앱에서 다양한 드래그 드롭 가능성에 대한 지시를 재사용 할 수 있기 때문에 마음에 듭니다. 필자는 컨트롤러에 다른 함수를 정의하고 on-drop 속성을 통해 지시문에 전달하기 만하면됩니다.

그러나 이것은 불행히도 Angular에 의해 격추 된 것으로 보입니다. 다른 사람이 동일한 디자인과 기능을 달성하는 방법에 관해서는 어떤 다른 방법이 있습니까? 그렇지만 Angular가 더 괜찮습니까? 여기

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 (10 월 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

그래서, 지시어는 드래그와 드롭 요소 ID를 반환하도록 수정됩니다. 그런 다음이 콜백까지 document.getElementById을하는 것입니다 :

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

    console.log(dragEl, dropEl); 
} 

가, 각도가 좋은 이유와 함께 자신의 expression sandboxingisecdom validation을 추가했다 가졌 :

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

내가 생각하는 lvlDropTarget 지침이다, 문제에 대한 해결책은 오히려 간단하다 -과 같이, dragEldropEl을 래핑하는 중간 객체를 사용

링크 기능에 :

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.controller('MainCtrl', function($scope, dropEvent) { 
    $scope.dropped = function(){ 
    console.log('dropped', dropEvent); 
    } 
}); 

DEMO : 다음

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(); 
     }); 
//... 

    } 
    } 
); 

는 컨트롤러/외부의 컨텍스트에서 사용하는

+0

좋은 제안입니다. 드래그를 위해'ngDraggable'을 사용하는 것으로 끝났지 만,이 대답의 정보는 여전히 가치가 있습니다. 나는 클레 톤 (Cleiton)에게 이것을 받아 들여 이것이 받아 들여지는 대답인지 결정하게된다 (만약 그가 당신에게 현상금을 준다면) – CodyBugstein