Cod*_*ein 4 dom parse-error angularjs angularjs-directive
我正在关注一个关于在Angular中实现Drag&Drop的很棒的教程,我最初在这个StackOverflow答案中找到了这个链接到作者的博客和GitHub代码.
当我实现它并在我的项目中测试它时,我得到了错误:
[$parse:isecdom] Referencing DOM nodes in Angular expressions is disallowed! Expression: dropped(dragEl, dropEl)
Run Code Online (Sandbox Code Playgroud)
根据Angular Docs,问题在于我引用了一个将DOM对象作为DOM属性中的参数的函数 - 它发生在这一行:
<div x-lvl-drop-target='true' x-on-drop='dropped(dragEl, dropEl)'>drop zone</div>
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,该on-drop属性将此dropped函数(在我的控制器中定义)传递给指令lvlDropTarget(在下面发布),该指令调用它来执行用户执行的拖放操作.我喜欢这种设计,因为它使该指令可以在同一个应用程序中重复使用许多不同的拖放可能性.实际上,我只需要在我的控制器中定义一个不同的函数,并通过on-drop属性将它传递给指令.
然而,不幸的是,这似乎被Angular击落了.有没有人有任何其他如何实现相同的设计和功能,但在某种程度上Angular更好吗?
这是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");
});
}
}
}
]);
Run Code Online (Sandbox Code Playgroud)
AngularJS现在给出了这个错误:"不允许在Angular表达式中引用DOM节点!",因为:on-drop ="controller.dropped(dragEl,dropEl)".
已提出以下解决方案:
返回DOM元素本身导致更新版本的AngularJS中的$ parse:isecdom错误.简单地说,让
dropped(...)回调句柄获取元素.

因此,如果接受此更改,则将修改该指令以返回拖放的元素ID.然后由你的回调来做document.getElementById:
$scope.dropped = function(dragId, dropId) {
var dragEl = document.getElementById(dragId);
var dropEl = document.getElementById(dropId);
console.log(dragEl, dropEl);
}
Run Code Online (Sandbox Code Playgroud)
话虽如此,Angular 有充分的理由在他们的表达沙盒中添加了isecdom验证:
AngularJS限制从表达式中访问DOM节点,因为它是执行任意Javascript代码的已知方法.
此检查仅在Angular表达式中的对象索引和函数调用上执行.这些是开发人员更难保护的地方.虚线成员访问(例如abc)不执行此检查 - 由开发人员决定不直接在范围链上公开此类敏感和强大的对象.
要解决此错误,请避免访问DOM节点.
我宁愿选择使用ngDraggable - 而不是试图规避这种保护- 它鼓励使用声明性视图,并且不需要控制器中的DOM操作.好决定.