如何将控制器注入AngularJS中的另一个控制器

Sco*_*tie 96 angularjs angularjs-scope angularjs-controller

我是Angular的新手并试图找出如何做事......

使用AngularJS,如何注入要在另一个控制器中使用的控制器?

我有以下代码段:

var app = angular.module("testApp", ['']);

app.controller('TestCtrl1', ['$scope', function ($scope) {
    $scope.myMethod = function () {
        console.log("TestCtrl1 - myMethod");
    }
}]);

app.controller('TestCtrl2', ['$scope', 'TestCtrl1', function ($scope, TestCtrl1) {
    TestCtrl1.myMethod();
}]);
Run Code Online (Sandbox Code Playgroud)

当我执行此操作时,我收到错误:

Error: [$injector:unpr] Unknown provider: TestCtrl1Provider <- TestCtrl1
http://errors.angularjs.org/1.2.21/$injector/unpr?p0=TestCtrl1Provider%20%3C-%20TestCtrl1
Run Code Online (Sandbox Code Playgroud)

我是否应该尝试在另一个控制器内使用控制器,还是应该将其作为服务?

PSL*_*PSL 129

如果您的目的是获取另一个组件的已实例化控制器,并且如果您遵循基于组件/指令的方法,则始终可以require是来自遵循特定层次结构的另一个组件的控制器(组件的实例).

例如:

//some container component that provides a wizard and transcludes the page components displayed in a wizard
myModule.component('wizardContainer', {
  ...,
  controller : function WizardController() {
    this.disableNext = function() { 
      //disable next step... some implementation to disable the next button hosted by the wizard
    }
  },
  ...
});

//some child component
myModule.component('onboardingStep', {
 ...,
 controller : function OnboadingStepController(){

    this.$onInit = function() {
      //.... you can access this.container.disableNext() function
    }

    this.onChange = function(val) {
      //..say some value has been changed and it is not valid i do not want wizard to enable next button so i call container's disable method i.e
      if(notIsValid(val)){
        this.container.disableNext();
      }
    }
 },
 ...,
 require : {
    container: '^^wizardContainer' //Require a wizard component's controller which exist in its parent hierarchy.
 },
 ...
});
Run Code Online (Sandbox Code Playgroud)

现在使用上面这些组件可能是这样的:

<wizard-container ....>
<!--some stuff-->
...
<!-- some where there is this page that displays initial step via child component -->

<on-boarding-step ...>
 <!--- some stuff-->
</on-boarding-step>
...
<!--some stuff-->
</wizard-container>
Run Code Online (Sandbox Code Playgroud)

您可以通过多种方式设置要求.

(无前缀) - 在当前元素上找到所需的控制器.如果找不到则抛出错误.

? - 尝试找到所需的控制器或将null传递给链接fn(如果未找到).

^ - 通过搜索元素及其父元素来定位所需的控制器.如果找不到则抛出错误.

^^ - 通过搜索元素的父项找到所需的控制器.如果找不到则抛出错误.

?^ - 尝试通过搜索元素及其父元素来定位所需的控制器,或者如果未找到则将null传递给链接fn.

?^^ - 尝试通过搜索元素的父元素来定位所需的控制器,或者如果未找到则将null传递给链接fn.



旧答案:

您需要注入$controller服务以实例化另一个控制器内的控制器.但请注意,这可能会导致一些设计问题.您始终可以创建遵循单一责任的可重用服务,并根据需要将它们注入控制器.

例:

app.controller('TestCtrl2', ['$scope', '$controller', function ($scope, $controller) {
   var testCtrl1ViewModel = $scope.$new(); //You need to supply a scope while instantiating.
   //Provide the scope, you can also do $scope.$new(true) in order to create an isolated scope.
   //In this case it is the child scope of this scope.
   $controller('TestCtrl1',{$scope : testCtrl1ViewModel });
   testCtrl1ViewModel.myMethod(); //And call the method on the newScope.
}]);
Run Code Online (Sandbox Code Playgroud)

在任何情况下,您都无法调用,TestCtrl1.myMethod()因为您已将方法附加$scope到控制器实例而不是控制器实例上.

如果您正在共享控制器,那么最好这样做: -

.controller('TestCtrl1', ['$log', function ($log) {
    this.myMethod = function () {
        $log.debug("TestCtrl1 - myMethod");
    }
}]);
Run Code Online (Sandbox Code Playgroud)

而消费时:

.controller('TestCtrl2', ['$scope', '$controller', function ($scope, $controller) {
     var testCtrl1ViewModel = $controller('TestCtrl1');
     testCtrl1ViewModel.myMethod();
}]);
Run Code Online (Sandbox Code Playgroud)

在第一种情况下,实际上$scope是您的视图模型,在第二种情况下,它是控制器实例本身.

  • 并且它取决于控制器提供的功能,如果你使它更像一个你需要在组件之间共享的视图模型,那很好但是如果它更多的是服务提供者功能那么我就会创建一个服务. (4认同)

che*_*ard 33

我建议你应该问的问题是如何将服务注入控制器.使用瘦控制器的胖服务是一个很好的经验法则,也就是使用控制器将服务/工厂(带有业务逻辑)粘合到您的视图中.

控制器在路由更改时收集垃圾,因此,例如,如果您使用控制器来保存呈现值的业务逻辑,那么如果应用程序用户单击浏览器后退按钮,您将在两个页面上丢失状态.

var app = angular.module("testApp", ['']);

app.factory('methodFactory', function () {
    return { myMethod: function () {
            console.log("methodFactory - myMethod");
    };
};

app.controller('TestCtrl1', ['$scope', 'methodFactory', function ($scope,methodFactory) {  //Comma was missing here.Now it is corrected.
    $scope.mymethod1 = methodFactory.myMethod();
}]);

app.controller('TestCtrl2', ['$scope', 'methodFactory', function ($scope, methodFactory) {
    $scope.mymethod2 = methodFactory.myMethod();
}]);
Run Code Online (Sandbox Code Playgroud)

这是一个工厂注入两个控制器的工作演示

另外,我建议阅读有关服务/工厂的本教程.


小智 13

无需在JS中导入/注入您的控制器.您可以通过HTML注入您的控制器/嵌套控制器.它对我有用.喜欢 :

<div ng-controller="TestCtrl1">
    <div ng-controller="TestCtrl2">
      <!-- your code--> 
    </div> 
</div>
Run Code Online (Sandbox Code Playgroud)

  • 是的...但我仍然觉得将所有常用元素放入服务并将服务注入相应的控制器会更好. (2认同)