【问题标题】:Multiple directives [myPopup, myDraggable] asking for new/isolated scope多个指令 [myPopup, myDraggable] 要求新的/隔离的范围
【发布时间】:2014-03-10 14:45:31
【问题描述】:

我为对话框(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);
            }
        }
    };
}]);

【问题讨论】:

  • 我看到,当我不小心将我的指令 js 文件包含两次时会发生类似的问题......所以也许这对某人有帮助......
  • 当我将部分移动到指令并忘记从模板中删除 ng-controller 时发生在我身上

标签: angularjs scope angularjs-directive


【解决方案1】:

来自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") {

并修改您的模板以绑定启用属性:

<div my-draggable="draggable" enabled="{{draggable}}"

DEMO

【讨论】:

  • 抱歉,DEMO 不起作用,因为 attrs.enabled 在链接部分中,因此它永远不会更新。 @Khanh TO
  • @Martin:我没有看到你将它绑定到任何地方。如果您需要在 attrs.enabled 更新时收到通知,您可以尝试scope.$watch(function(){ return attrs.enabled },function (value){});
【解决方案2】:

一个 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 函数

【讨论】:

  • 好的,现在我已经解决了。这是我的Plunker
  • 太棒了,@Martin!如果解决了这个问题,您会标记一个已接受的答案并为相关答案投票吗?谢谢!
【解决方案3】:

我的错误类似:

错误:[$compile:multidir] 多个指令 [groups, groups] 要求新的/隔离的范围:

在我的情况下,我有重复声明

 .component('groups', new GroupsComponent()); 

在 app.js/app.ts 文件中

同时在组件本身上

const groups = angular.module('groups', ['toaster'])
.component('groups', new GroupsComponent());

从 app.js/app.ts 中删除它解决了这个问题。

【讨论】:

    【解决方案4】:

    有办法解决它。

    您不会隔离指令的范围,而是使用 $new method 创建一个新的隔离范围。此方法创建一个新的子范围,如果您在第一个参数处使用 true,它将创建一个隔离范围:

    如果为 true,则该范围在原型上不会从父范围继承。范围是孤立的,因为它看不到父 > 范围属性。创建小部件时,小部件不会意外读取父状态很有用。

    但这不是问题,因为我们可以通过指令链接函数访问私有作用域,因此可以与“父”和隔离作用域并行工作,成为具有隔离作用域的指令的非常接近的行为。

    请看下面的例子:

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

    我将此工作开发为验证指令,效果很好。

    【讨论】:

    • 无论如何我们可以用这个进行双向数据绑定?
    • 是的,你可以。但它是用 $watch 模拟的
    【解决方案5】:

    我遇到了类似的情况。如果它不会弄乱您的布局并且您肯定需要在两个指令上都有一个隔离范围,我的建议是从 myPopup 指令定义中删除属性 replace: true

    【讨论】:

      【解决方案6】:

      当我压缩我的应用程序时,我已经包含了我的指令 js 文件两次。这导致了错误。

      【讨论】:

      • 阅读bennadel.com/blog/… 之后,我向下滚动发现您已经回答了它。这需要一个赞成票,因为当您意外地错误地定义了两次组件时,其余的只是分散注意力。例如:angular.module('myapp', []).component('thing', Thing).component('thing', Thing)。该错误将在渲染后导致此错误: > 多个指令 [thing, thing] 要求在:
      【解决方案7】:

      从你的“myDraggable”指令中去掉范围:{ enabled: '=myDraggable'},你不需要它。所以:

        return {
          restrict: 'A',
          replace: false,
          link: function (scope, elm, attrs) {
      

      【讨论】:

      • 抱歉,由于这部分原因,这不起作用if (scope.enabled === true) { elm.bind('mousedown', function ($event) {@Matthias
      猜你喜欢
      • 1970-01-01
      • 2017-07-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多