Доступ к изолированной родительской области из включенной директивы

Я столкнулся с ситуацией, которая кажется противоположной любому подобному вопросу здесь, в StackOverflow.

У меня есть директива <scroll>, которая просто оборачивает любое содержимое в какой-то прокручиваемый div. Выглядит это примерно так:

.directive('scroll', ['$document','$parse', function ($document,$parse) {
return {
    restrict: 'E',
    replace: true,
    transclude: true,
    scope:false,
    template:
        '<div class="scroll">' +
            '<div class="content" data-ng-transclude>' +
            '</div>' +
        '</div>',
    link: function (scope, element, attr) {
        // some code here....
    }
};
}]);

Это прекрасно работает само по себе.

Теперь у меня есть другая директива под названием <editor>, которая имеет изолированную область действия и использует <scroll> в своем шаблоне. <editor> выглядит примерно так:

.directive('editor', ['$document', function ($document){
return {
    restrict: 'EA',
    replace: true,
    transclude: false,
    scope:true,
    template:
        '<div>' +
            '....<scroll>....</scroll>....' +
        '</div>',
    link: function (scope, element, attrs) {
        .....
    }
};
}]);

Теперь вот в чем дело: мне нужно получить доступ к области <editor> из функции ссылки <scroll> (где написано "здесь какой-то код"), но по какой-то причине я не могу. Переменная scope в функции ссылки <scroll> практически пуста, и scope.$parent дает мне указанный выше контроллер, пропуская <editor>, который должен мешать.

Я пытался играть с ng-transclude в разных местах в <editor> и пытался использовать $emit, и я действительно ничего не знаю об этом - я думаю, что изоляция области действия изолирует "меня и все, что ниже меня" от того, что выше, но кажется, что область действия изоляция просто убирает "меня" из дерева областей видимости...

Надеюсь, это достаточно ясно, спасибо.


person motig88    schedule 05.08.2013    source источник
comment
Посмотрите видео Джона Линдквиста об обмене данными между директивами. Это может заставить вас двигаться в правильном направлении.   -  person Jonathan Palumbo    schedule 05.08.2013
comment
Вы должны стараться не делать этого таким образом, потому что теперь вы ограничиваете свою директиву прокрутки жестко закодированной в директиве вашего редактора. Это классический случай связанности, который ограничивает возможность повторного использования ваших директив. При этом существует масса способов сделать это. Лучший способ, вероятно, использовать $emit или $broadcast для отправки событий. Если вы сделаете это правильно, вы сможете остаться развязанным и по-прежнему использовать свой свиток в другом месте.   -  person Jonathan Rowny    schedule 05.08.2013
comment
Меня просто осенило, почему это происходит, хотя у меня пока нет решения: дело в том, что метод link внутренней директивы срабатывает перед родительским, поэтому кажется, что я не могу получить доступ к области действия родителя из link функция, но может из разметки с {{}}. Возможно, решение состоит в том, чтобы внутренняя директива $watch была готова для верхней директивы, прежде чем использовать $parse(...)(scope) для доступа к ней.   -  person motig88    schedule 05.08.2013


Ответы (1)


Код, показанный для директивы editor, не создает изолированную область. Вместо этого создается новая дочерняя область, которая прототипически наследуется от родительской/содержащей области.

Так как директива scroll имеет scope: false, она будет использовать дочернюю область, которую создает editor — нет необходимости в $parent.

Да, функция ссылки для editor будет выполняться после функции ссылки для scroll. Однако функция контроллера для editor (если вы ее определили) будет выполняться перед функцией связи для scroll:

app.directive('scroll', ['$document','$parse', function ($document,$parse) {
return {
    restrict: 'E',
    replace: true,
    transclude: true,
    scope:false,
    template:
        '<div class="scroll">' +
            '<div class="content" data-ng-transclude>' +
            '</div>' +
        '</div>',
    link: function (scope, element, attr) {
        // some code here....
        console.log('link_editor=',scope.link_editor);  // value is "undefined"
        console.log('ctrl_editor=',scope.ctrl_editor);  // value is "true"
    }
};
}]);
app.directive('editor', ['$document', function ($document){
return {
    restrict: 'EA',
    replace: true,
    transclude: false,
    scope:true,
    template:
        '<div>' +
            'stuff <scroll>content to scroll</scroll> more stuff' +
        '</div>',
    link: function (scope, element, attrs) {
        scope.link_editor = true;
    },
    controller: function($scope) {
        $scope.ctrl_editor = true;
    }
};
}]);
person Mark Rajcok    schedule 05.08.2013
comment
Спасибо! Похоже, это может быть лучшим решением, чем обходной путь, который я сделал (то есть, если определенное свойство <editor>, которое мне нужно, не определено во время <scroll> -> link, я $watch для свойства <editor> мне нужно, а затем запускаю свой код). Сначала я попробую это завтра утром, это может упростить код, хотя обходной путь, вероятно, останется, поскольку я не могу полагаться на того, кто использует <scroll> для реализации контроллера. - person motig88; 05.08.2013
comment
@Mark Rajcok, простите за полусторонний вопрос: почему editor.link() запускается после scroll.link(). Я подумал, что документы AJS подразумевают, что родительские узлы $компилируются и $связываются перед дочерними элементами, и здесь у нас есть ‹editor›‹scroll/›‹/editor›, так что порядок не будет таким: 1) editor.compile(), 2) e.controller(), 3) e.link(), 4) scroll.compile(), 5) scroll.controller; 6) прокрутка.ссылка()? Влияют ли в этом случае объявления включений или областей действия на порядок? - person Nikita; 28.01.2014
comment
update выше: я был неправ - см. здесь. Пока не ясно, как/изменит ли трансклюзия это. - person Nikita; 28.01.2014