我为对话框(myPopup)编写了一个指令,另一个用于拖动此对话框(myDraggable),但我总是得到错误:
多个指令[myPopup,myDraggable]要求新/隔离范围
这是一个Plunker:http://plnkr.co/edit/kMQ0hK5RnVw5xOBdDq5P?p=preview
我该怎么办?
JS代码:
var app = angular.module('myApp', []);
function myController($scope) {
$scope.isDraggable = true;
}
app.directive('myPopup', [
function () {
"use strict";
return {
restrict: 'E',
replace: true,
transclude: true,
template: '<div my-draggable="draggable"class="dialog"><div class="title">{{title}}</div><div class="content" ng-transclude></div></div>',
scope: {
title: '@?dialogTitle',
draggable: '@?isDraggable',
width: '@?width',
height: '@?height',
},
controller: function ($scope) {
// Some code
},
link: function (scope, element, attr) {
if (scope.width) {
element.css('width', scope.width);
}
if (scope.height) {
element.css('height', scope.height);
}
}
};
}
]);
app.directive('myDraggable', ['$document',
function ($document) {
return {
restrict: 'A',
replace: false,
scope: { enabled: '=myDraggable' },
link: function (scope, elm, attrs) {
var startX, startY, initialMouseX, initialMouseY;
if (scope.enabled === true) {
elm.bind('mousedown', function ($event) {
startX = elm.prop('offsetLeft');
startY = elm.prop('offsetTop');
initialMouseX = $event.clientX;
initialMouseY = $event.clientY;
$document.bind('mousemove', mousemove);
$document.bind('mouseup', mouseup);
$event.preventDefault();
});
}
function getMaxPos() {
var computetStyle = getComputedStyle(elm[0], null);
var tx, ty;
var transformOrigin =
computetStyle.transformOrigin ||
computetStyle.webkitTransformOrigin ||
computetStyle.MozTransformOrigin ||
computetStyle.msTransformOrigin ||
computetStyle.OTransformOrigin;
tx = Math.ceil(parseFloat(transformOrigin));
ty = Math.ceil(parseFloat(transformOrigin.split(" ")[1]));
return {
max: {
x: tx + window.innerWidth - elm.prop('offsetWidth'),
y: ty + window.innerHeight - elm.prop('offsetHeight')
},
min: {
x: tx,
y: ty
}
};
}
function mousemove($event) {
var x = startX + $event.clientX - initialMouseX;
var y = startY + $event.clientY - initialMouseY;
var limit = getMaxPos();
x = (x < limit.max.x) ? ((x > limit.min.x) ? x : limit.min.x) : limit.max.x;
y = (y < limit.max.y) ? ((y > limit.min.y) ? y : limit.min.y) : limit.max.y;
elm.css({
top: y + 'px',
left: x + 'px'
});
$event.preventDefault();
}
function mouseup() {
$document.unbind('mousemove', mousemove);
$document.unbind('mouseup', mouseup);
}
}
};
}]);
答案 0 :(得分:62)
来自docs:
应用于的多个不兼容指令的示例场景 相同的元素包括:
请求隔离范围的多个指令。
以相同名称发布控制器的多个指令。
使用transclusion选项声明的多个指令。
多个指令试图定义模板或模板URL。
尝试删除myDraggable
指令中的隔离范围:
app.directive('myDraggable', ['$document',
function ($document) {
return {
restrict: 'A',
replace: false,
scope: { enabled: '=myDraggable' }, //remove this line
将scope.enabled
替换为attrs.enabled
:
if (attrs.enabled == "true") {
修改模板以绑定enable属性:
<div my-draggable="draggable" enabled="{{draggable}}"
答案 1 :(得分:22)
DOM元素正在与您尝试的隔离范围发生冲突。因此,您应该始终问自己是否需要隔离范围。
考虑删除myDraggable
上的隔离范围,插入myDraggable值(就像使用isDraggable一样),并访问link
函数中的属性。
<div class="draggable" my-draggable="{{isDraggable}}">I am draggable {{isDraggable}}</div>
...
replace: false,
link: function (scope, elm, attrs) {
var startX, startY, initialMouseX, initialMouseY,
enabled = attrs.myDraggable === 'true';
if (enabled === true) {
...
查看更新后的Plunker here并注意myPopup模板中的更改。
如果要查看myDraggable属性更改,请执行以下操作:
attrs.$observe('myDraggable', function(iVal) {
enabled = iVal === 'true';
// AND/OR
if (iVal === 'true') doSomething();
});
参见Angular Attribute Docs $ observe function
答案 2 :(得分:6)
我的错误类似:
错误:[$ compile:multidir]多个指令[groups,groups]要求新的/隔离范围:
在我的情况下,我有重复声明
.component('groups', new GroupsComponent());
同时在组件本身上
const groups = angular.module('groups', ['toaster'])
.component('groups', new GroupsComponent());
从app.js / app.ts中删除它解决了这个问题。
答案 3 :(得分:4)
我遇到了类似的情况。如果它没有弄乱你的布局,你肯定需要在两个指令上都有一个隔离范围,我的建议是从myPopup指令定义中删除属性replace: true
。
答案 4 :(得分:3)
有办法解决这个问题。
您不会隔离指令的范围,而是使用$new method创建一个新的隔离范围。此方法创建一个新的子范围,如果在第一个参数中使用true,它将创建一个隔离的范围:
如果为true,则作用域不会从父作用域原型继承。范围是隔离的,因为它看不到父&gt;范围属性。创建窗口小部件时,窗口小部件不会意外地读取父状态。
但这不是问题,因为我们可以通过指令链接函数访问私有范围,因此可以与“父”并行隔离范围并与具有隔离范围的指令的非常接近的行为进行协作。 / p>
以下示例:
app.directive('myDraggable', ['$document',
function ($document) {
return {
restrict: 'A',
replace: false,
scope: false,
//scope: { enabled: '=myDraggable', oneWayAttr: "@" }, //Just for reference I introduced a new
link: function(parentScope, elem, attr) {
var scope = parentScope.$new(true); //Simulated isolation.
scope.oneWayAttr = attr.oneWayAttr; //one-way binding @
scope.myDraggable = parentScope.$parent.$eval(attr.myDraggable);
scope.watchmyDraggable = function () {
return scope.myDraggable = parentScope.$parent.$eval(attr.myDraggable); //parent -> isolatedscope
};
scope.$watch(scope.watchmyDraggable, function(newValue, oldValue) {
//(...)
});
parentScope.innerScope = scope; //If you need view access, you must create a kind of symbolic link to it.
//(...)
}
我将这项工作开发为验证指令,这非常有效。
答案 5 :(得分:1)
当我压缩我的应用程序时,我已经将我的指令js文件包含了两次。这导致了错误。
答案 6 :(得分:0)
忽略范围:{enabled:'= myDraggable'}来自您的“myDraggable” - 您不需要它。所以:
return {
restrict: 'A',
replace: false,
link: function (scope, elm, attrs) {