Вложенные директивы и родительские области

Проблема, с которой я столкнулся, можно увидеть на странице http://jsfiddle.net/miketheanimal/2CcYp/13/ Это сводит мою проблему к минимуму.

У меня есть контроллер «main», директива «external», которая включает в себя, и директива «inner», которая этого не делает. Каждая директива имеет изолированную область действия и контроллер. Контроллеры main и директивы устанавливают $ scope._name = '...', чтобы я мог различать их.

var module = angular.module('miketa', []);
function main ($scope) {
    $scope._name = 'main' ;
} ;
module.directive('outer', function() {
    return {
        restrict: 'E',
        replace: true,
        transclude: true,
        scope: {},
        template: '<div><div ng-transclude></div></div>',
        controller: [ '$scope', function($scope) {
            $scope._name = 'outer' ;
            document.getElementById('opn').innerHTML = $scope.$parent._name ;
        }]}});
module.directive('inner', function() {
    return {
        restrict: 'E',
        replace: true,
        scope: {},
        template: '<div></div>',
        controller: [ '$scope', function($scope) {
            $scope._name = 'inner' ;
            document.getElementById('ipn').innerHTML = $scope.$parent._name ;
        }]}});

HTML вкладывает их как main -> external -> inner. Функции контроллера в директивах копируют имя своей родительской области видимости (например, * $ scope. $ Parent._name) в визуализированный HTML-код (извинения за непосредственное управление DOM, это был самый простой способ отобразить имена!).

Я ожидал бы, что external покажет имя из контроллера (т. Е. «Main»), который есть, и я бы ожидал, что inner покажет имя из external (т.е. «внешний»), которого нет, скорее он также показывает «main».

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


person Mike Richardson    schedule 26.09.2013    source источник
comment
Это довольно логично, я думаю, что ваш внешний прицел изолирован, так как вы можете унаследовать его?   -  person Thomas Pons    schedule 26.09.2013
comment
Да, области изолированы, поэтому они не наследуются прототипом, но у них есть родительские области (родительский бит $ scope. $), И они, похоже, не работают так, как я ожидал (внутренняя - ›внешняя -› главный). Как я отмечал в последнем абзаце, это становится проблемой, когда я пытаюсь выполнить привязку между областями действия internal и external (т. Е. Во внутренней области : {внутренняя переменная: '= внешняя переменная'}).   -  person Mike Richardson    schedule 26.09.2013
comment
Ах, ng-transclude установил для ng-scope значение false!   -  person Thomas Pons    schedule 26.09.2013


Ответы (1)


На самом деле это не ошибка, а желаемое поведение. Из документации по службе $compile:

В типичной настройке виджет создает изолированную область видимости, но включение является не дочерним, а родственным по отношению к изолированной области. Это позволяет виджету иметь частное состояние и привязку включения к родительской (предварительно изолированной) области.

См. Также: Почему область действия ng-transclude не является дочерней областью ее директивы - если директива имеет изолированную область видимости?

Если вам действительно нужно заставить его работать, забудьте ng-transclude и выполните:

var module = angular.module('miketa', []);

function main($scope) {
    $scope._name = 'main';
};
module.directive('outer', function () {
    return {
        restrict: 'E',
        replace: true,
        scope: {},
        template: '<div><inner></inner></div>',
        controller: ['$scope', function ($scope) {
            $scope._name = 'outer';
            document.getElementById('opn').innerHTML = $scope.$parent._name;
        }]
    }
});
module.directive('inner', function () {
    return {
        restrict: 'E',
        replace: true,
        scope: {},
        template: '<div></div>',
        controller: ['$scope', function ($scope) {
            $scope._name = 'inner';
            document.getElementById('ipn').innerHTML = $scope.$parent._name;
        }]
    }
});

И вуаля! Оно работает.

person Thomas Pons    schedule 26.09.2013
comment
Я задавался вопросом, связано ли с этим transclude, я нашел какие-то другие посты, но не совсем связанные. Но ваше изменение скорее делает external бессмысленным, я мог бы с таким же успехом свернуть его во internal. Я пытаюсь создать директиву outer, которая может обернуть различный контент (например, обернуть inner1 и inner2 и т. Д.) . Как я могу это сделать? - person Mike Richardson; 26.09.2013
comment
Никакой какой-либо ng-trnasclude не изолирует область видимости, которую вы должны принять! Это логика включения в AngularJSn, если вы читаете цепочку ссылок и документы - person Thomas Pons; 26.09.2013
comment
Lol удачи :)! Directive API - самая мощная, но чертовски сложная часть AngularJS! В любом случае, возможно, вам придется принять или удалить вопрос, который я не знаю - person Thomas Pons; 26.09.2013