Подтвердить что ты не робот

Несколько директив [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);
            }
        }
    };
}]);
4b9b3361

Ответ 1

От docs:

Пример сценариев нескольких несовместимых директив, применяемых к один и тот же элемент:

Несколько директив, запрашивающих изолированную область.

Несколько директив, публикующих контроллер под тем же именем.

Несколько директив, объявленных с опцией перехода.

Несколько директив, пытающихся определить шаблон или шаблон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}}"

DEMO

Ответ 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 здесь и обратите внимание на изменение в шаблоне myPopup.

Если вы хотите увидеть изменения атрибута myDraggable, выполните следующее:

attrs.$observe('myDraggable', function(iVal) {
  enabled = iVal === 'true';
  // AND/OR
  if (iVal === 'true') doSomething();
});

См. Angular Документы атрибута $Функция наблюдения

Ответ 3

моя ошибка была похожа:

Ошибка: [$ compile: multidir] Несколько директив [группы, группы], запрашивающие новую/выделенную область действия:

В моем случае у меня было дублирующее объявление

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

в файле app.js/app.ts

и в то же время на самом компоненте

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

Удаление его из app.js/app.ts исправило проблему.

Ответ 4

Я столкнулся с подобной ситуацией. Если это не испортит ваш макет, и вам определенно нужно обладать изоляцией в обеих директивах, мое предложение состояло в том, чтобы удалить свойство replace: true из определения директивы myPopup.

Ответ 5

Есть способ обойти его.

Вы не будете изолировать область действия директивы, вместо нее мы создадим новую изолированную область, используя $new method. Этот метод создает новую дочернюю область, если вы используете true в первом параметре, он создаст изолированную область:

Если true, то область не прототипически наследуется от родительской области. Область выделена, так как она не может видеть родительские свойства области. При создании виджетов полезно, чтобы виджет не случайно прочитал родительское состояние.

Но это не проблема, потому что у нас есть доступ к частной сфере с помощью функции linking link, поэтому можно работать параллельно с "родительским" и изолированным областью в очень близкое поведение директивы с изолированной областью.

В следующем примере:

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

        //(...)
        }

Я разработал эту работу для директивы валидации, которая работает очень хорошо.

Ответ 6

Оставьте область действия: {enabled: '= myDraggable}} из вашего "myDraggable" -directive, который вам не нужен. Итак:

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

Ответ 7

Я дважды включил свой файл директивы js, когда сжал приложение. Это вызвало ошибку.