Angularjs: inject required directive-controller into the controller instead of the link function

后端 未结 3 744
挽巷
挽巷 2020-12-15 22:33

Normal use cases in angular

If you have a parent directive and a child directive you create methods in the controller of the parent directive and re

相关标签:
3条回答
  • 2020-12-15 23:13

    Actually there is another way that is less verbose and is used by the angular ngModel itself:

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

    Basically they use the fact that the controllers are stored into the data property of the directive dom element.

    Still a bit wired, but less verbose and easier to understand.

    I don't see a reason why you cannot pass the required controllers into the injection locals for the directive controller.

    0 讨论(0)
  • 2020-12-15 23:19

    The question is in what order directives are compiled and linked. Suppose we have a html structure like this:

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

    and the coresponding (simplyfied) directives with a lot of debug output:

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

    we got the following output:

    top compile
    middle compile
    bottom compile
    
    top pre
    middle pre
    bottom pre
    
    middle method
    top method
    
    bottom post
    middle post
    top post
    

    As we can see first the compile function is called. Then the pre linking function is called and after that the post linking function is called. compile and pre are going from top to bottom and post goes from bottom to top. So we have to set the controller in the pre linking function.

    0 讨论(0)
  • 2020-12-15 23:38

    Taken from romario333's comment: The cleanest solution is to simply use

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

    From the docs:

    controller(name) - retrieves the controller of the current element or its parent. By default retrieves controller associated with the ngController directive. If name is provided as camelCase directive name, then the controller for this directive will be retrieved (e.g. 'ngModel').

    $element can be injected into your directive controller.

    0 讨论(0)
提交回复
热议问题