【问题标题】:From an AngularJS controller, how do I resolve another controller function defined in the module (dynamic ng-controller)?从 AngularJS 控制器,如何解析模块中定义的另一个控制器功能(动态 ng-controller)?
【发布时间】:2014-02-07 20:58:20
【问题描述】:

自解释小提琴:http://jsfiddle.net/5FG2n/6/

我需要根据其名称作为字符串动态选择要在运行时使用的控制器。该字符串将从配置对象中读取。

在下面的代码中,我目前将InnerCtrlAsLocalVariable 分配给$scope.dynamicCtrl。我该如何将InnerCtrlFromModule 分配给该属性?

查看:

<div ng-app='app' ng-controller='OuterCtrl'>
    <div ng-controller='dynamicCtrl'>
        {{message}}
    </div>
</div>

JS:

var InnerCtrlAsLocalVariable = ['$scope',
    function($scope) {
        $scope.message = 'from controller as local variable - do not want'
    }
];

angular.module('app', []) 

    .controller('OuterCtrl', ['$scope', 

        function($scope) {
            // Instead of doing this...
            $scope.dynamicCtrl = InnerCtrlAsLocalVariable;

            // ...I want to do something like this:
            // $scope.dynamicCtrl = resolveCtrl('InnerCtrlFromModule');                                               
        }
    ])

    .controller('InnerCtrlFromModule', ['$scope',
        function($scope) {
            $scope.message = 'from controller defined in module - want';
        }
    ]);

【问题讨论】:

  • 为什么需要将控制器分配给变量?您通过服务共享数据。
  • 虽然我真的不明白目的,你可以选择动态模板(inner-local-template.html,inner-module-template.html')而不是选择动态控制器。
  • 这不是为了共享数据,这是为了让我可以在运行时动态选择控制器。
  • 我已经通过绑定 ng-include 上的 src 属性来动态选择模板。但是同一个模板可能在不同的情况下使用不同的控制器。因此,我需要避免将控制器名称硬编码到模板中。
  • 我找不到动态注入或解析控制器的方法。

标签: javascript angularjs angularjs-scope angularjs-controller


【解决方案1】:

您可以尝试编写自定义指令:

.directive("ngDynamicController",function($compile){
        return {
            terminal: true, 
            priority: 1000,
            link:function(scope,element,attr){
                var controllerProperty = scope[attr.ngDynamicController];
                element.attr('ng-controller', controllerProperty);
                element.removeAttr("ng-dynamic-controller"); 
                $compile(element)(scope);
            }
        }
    })

如果您需要更多信息,为什么我们必须添加 terminal: truepriority: 1000。看看我对这个问题的回答:Add directives from directive in AngularJS

DEMO

您可以尝试将其作为值注入:

angular.module('app', [])
        .value('InnerCtrl',InnerCtrlAsLocalVariable)
        .controller('OuterCtrl', ['$scope','InnerCtrl', 
        function($scope, InnerCtrl) { //inject the value into the function
            $scope.dynamicCtrl = InnerCtrl;                                          
        }
    ])

DEMO

或者使用$injector动态解析:

var InnerCtrlAsLocalVariable = ['$scope',
            function($scope) {
                $scope.message = 'from controller defined in module - want';
            }
        ]

    angular.module('app', [])
        .value('InnerCtrl',InnerCtrlAsLocalVariable)
        .controller('OuterCtrl', ['$scope','$injector', 
            function($scope, $injector) { //inject the $injector service.

                // resolve the value dynamically
                $scope.dynamicCtrl = $injector.get('InnerCtrl');

            }
        ])

        .controller('InnerCtrlFromModule', InnerCtrlAsLocalVariable)

DEMO

您可以使用$controller 服务动态创建控制器实例,从该实例中我们可以使用constructor 属性检索构造函数

 angular.module('app', [])
        .controller('OuterCtrl', ['$scope','$controller', 
            function(scope, $controller) {

                scope.dynamicCtrl = $controller('InnerCtrlFromModule',{$scope:scope.$new()}).constructor;

            }
        ])

        .controller('InnerCtrlFromModule',['$scope', function($scope) {
                $scope.message = 'from controller defined in module - want';
            }])

DEMO

【讨论】:

  • 这是我的代码的精简版。我想在运行时根据其名称作为字符串动态选择控制器。控制器名称将从配置中读取。例如,可能有十个不同的控制器。我不想注入所有这些。此外,如果控制器没有使用 controller() 方法定义,那么如何使用 $controller 服务对其进行单元测试,同时仍然使用 minification-proof 语法?
  • 我认为,$injector 仅适用于提供,不适用于控制器。您的示例有效,因为您将控制器公开为值(提供的种类)。
  • @Mike Chamberlain:我想通了,看看我的上一个演示
  • @Fizer Khan:我想通了,看我的上一个演示
  • @Mike Chamberlain:使用自定义指令查看我的上一个演示。
【解决方案2】:

您不需要动态选择控制器。使用单个控制器并使用 DI 为该控制器提供不同的功能。

angular.module('app', [])
    .service('ControllerService', function() {
        this.get = function(controllerName) {
            // ... do your logic for returning the controller functionality here
            if (controllerName == "fooController") {
                return {
                    foo: function() { return "foo" }
                }
            }
            else {
                return {
                    foo: function() { return "bar" }
                }
            }
        });
    })
    .controller('SingleController', ['$scope', 'ControllerService',
        function($scope, ControllerService) {
            $scope.functionality = ControllerService.get('fooController');
        });

您绑定到控制器上的functionality 对象:

<div ng-controller="SingleController">
   <p>{{functionality.foo()}}</p>
</div>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-08-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-13
    • 2016-01-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多