Angularjs: вводят требуемый директивный контроллер в контроллер вместо функции соединения

Нормальные варианты использования в angular

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

Мой пример использования

У меня есть вариант использования, когда дочерняя директива является родителем для другой директивы. У меня есть указатель сверху, который требуется директивой посередине. Средняя директива требуется последней директивой внизу.

В легком мире я мог бы просто создать метод ссылок и контроллер для средней директивы. Метод link обрабатывает все с помощью верхнего контроллера, а средний контроллер передается в нижнюю директиву.

В моем случае методы в контроллере средней директивы должны вызывать методы в родительском объекте, поэтому мне нужен верхний контроллер в среднем контроллере, а не в функции ссылки из средней директивы!

Вопрос

Как я могу ввести требуемый контроллер в контроллер вместо функции ссылки

angular.module('app').directive('top', function () {
    return {
        $scope: true,
        templateUrl: "top.html",
        controller: function() {
            this.topMethod = function() {
                // do something on top
            }
        }
    }
});

angular.module('app').directive('middle', function () {
    return {
        $scope: true,
        templateUrl: "middle.html",
        require: "^top",
        controller: function($scope, $attrs, topController) {
            this.middleMethod = function() {
                // do something in the middle

                // call something in top controller, this is the part that makes everything so complicated
                topController.topMethod();
            }
        }
    }
});

angular.module('app').directive('bottom', function () {
    return {
        $scope: true,
        templateUrl: "bottom.html",
        require: "^middle",
        link: function(scope, element, attrs, middleController) {
            $scope.bottomMethod = function() {
                // do something at the bottom

                // call something in the parent controller
                middleController.middleMethod();
            }
        }
    }
});

Ответы

Ответ 1

На самом деле существует еще один способ, который менее подробен, и используется самим angular ngModel:

var parentForm = $element.inheritedData('$formController') || ....

В основном они используют тот факт, что контроллеры хранятся в свойстве data элемента директивного dom.

Все еще немного проводной, но менее подробный и понятный.

Я не вижу причины, по которой вы не можете передать требуемые контроллеры в локаторы инъекций для контроллера директивы.

Ответ 2

Вопрос в том, какие директивы упорядочены и связаны. Предположим, что мы имеем такую ​​структуру html:

<div top>
   <div middle>
      <div bottom></div>
   </div>
</div>

и соответствующие (простые) директивы с большим количеством отладочного вывода:

.directive('top', function() {
    return {
        controller : function($scope, $element, $attrs) {
            this.topMethod = function() {
                console.log('top method');
            }
        },
        compile : function($element, $attrs) {
            console.log('top compile');
            return {
                pre : function($scope, $element, $attrs) {
                    console.log('top pre');
                },
                post : function($scope, $element, $attrs) {
                    console.log('top post');
                }
            };
        }
    }
})

.directive('middle', function() {
    return {
        require : "^top",
        controller : function($scope, $element, $attrs) {
            this.middleMethod = function() {
                console.log('middle method');
                $scope.topController.topMethod();
            }
        },
        compile : function($element, $attrs) {
            console.log('middle compile');
            return {
                pre : function($scope, $element, $attrs, topController) {
                    console.log('middle pre');
                    $scope.topController = topController;
                },
                post : function($scope, $element, $attrs, topController) {
                    console.log('middle post');
                }
            };
        },
    }
})

.directive( 'bottom', function() {
    return {
        require : "^middle",
        compile : function($element, $attrs) {
            console.log('bottom compile');
            return {
                pre : function($scope, $element, $attrs, middleController) {
                    console.log('bottom pre');
                    middleController.middleMethod();
                },
                post : function($scope, $element, $attrs, middleController) {
                    console.log('bottom post');
                }
            };
        }
    }
})

мы получили следующий результат:

top compile
middle compile
bottom compile

top pre
middle pre
bottom pre

middle method
top method

bottom post
middle post
top post

Как мы видим, сначала вызывается функция компиляции. Затем вызывается функция предварительной привязки, после чего вызывается функция связывания сообщений. compile и pre идут сверху вниз, а пост - снизу вверх. Поэтому мы должны установить контроллер в функцию предварительной привязки.

Ответ 3

Взято из комментария romario333: Самое чистое решение - просто использовать

var topController = $element.controller('top') // pass directive name or controller name

Из документов:

controller (name) - возвращает контроллер текущего элемента или его родителя. По умолчанию получает контроллер, связанный с директивой ngController. Если имя указано как имя директивы camelCase, тогда будет восстановлен контроллер для этой директивы (например, "ngModel" ).

Элемент

$может быть введен в ваш контроллер.