web-dev-qa-db-ja.com

新しい/分離されたスコープを要求する複数のディレクティブ[myPopup、myDraggable]

ダイアログ用のディレクティブ(myPopup)とこのダイアログのドラッグ用のディレクティブ(myDraggable)を作成しましたが、常にエラーが発生します。

新しい/分離されたスコープを要求する複数のディレクティブ[myPopup、myDraggable]

ここにプランカーがあります: 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);
            }
        }
    };
}]);
51
Martin

docs から:

同じ要素に適用される複数の互換性のないディレクティブのシナリオの例は次のとおりです。

孤立したスコープを要求する複数のディレクティブ

同じ名前でコントローラーを公開する複数のディレクティブ。

トランスクルージョンオプションで宣言された複数のディレクティブ。

テンプレートまたはtemplateURLを定義しようとする複数のディレクティブ。

myDraggableのディレクティブの分離スコープを削除してみてください。

app.directive('myDraggable', ['$document',
    function ($document) {
    return {
        restrict: 'A',
        replace: false,
        scope: { enabled: '=myDraggable' }, //remove this line

scope.enabledattrs.enabledに置き換えます:

if (attrs.enabled == "true") {

そして、テンプレートを変更して、enable属性をバインドします。

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

DEMO

62
Khanh TO

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関数を参照してください

22

私のエラーは似ていました:

エラー:[$ compile:multidir]複数のディレクティブ[グループ、グループ]で新しい/分離されたスコープを要求:

私の場合、私は

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

app.js/app.tsファイル内

同時にコンポーネント自体にも

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

App.js/app.tsから削除すると、問題が修正されました。

7
d689p

私は同様の状況に遭遇しました。レイアウトが混乱せず、両方のディレクティブに分離スコープを確実に必要とする場合、myPopupディレクティブ定義からプロパティreplace: trueを削除することをお勧めします。

4
Mihai Popescu

それを回避する方法があります。

ディレクティブのスコープを分離するのではなく、代わりに $ new method を使用して新しい分離スコープを作成します。このメソッドは、新しい子スコープを作成します。1番目のパラメーターで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.

        //(...)
        }

私はこの回避策を検証ディレクティブに向けて開発しましたが、これは非常にうまく機能します。

4
LeonanCarvalho

アプリを圧縮するときに、ディレクティブjsファイルを2回インクルードしました。これによりエラーが発生しました。

1
Gerfried

スコープを外します:{有効: '= myDraggable'}不要な「myDraggable」ディレクティブから。そう:

  return {
    restrict: 'A',
    replace: false,
    link: function (scope, Elm, attrs) {
0
mhtsbt