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


97

我是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();
}]);

执行此操作时,出现错误:

Error: [$injector:unpr] Unknown provider: TestCtrl1Provider <- TestCtrl1
http://errors.angularjs.org/1.2.21/$injector/unpr?p0=TestCtrl1Provider%20%3C-%20TestCtrl1

我是否应该甚至尝试在另一个控制器中使用一个控制器,还是应该将此服务用作服务?


2
您不能将控制器相互注入。是的,您应该改为TestCtrl1使用服务。
Sly_cardinal

确切地说,使用服务
Miguel Mota 2014年

3
如果我必须更新绑定到视图的控制器的属性该怎么办。此属性受另一个控制器中发生的事件影响。
Ankit Tanna

Answers:


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

现在,以上这些组件的用法可能是这样的:

<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>

您可以通过多种方式设置require

(无前缀)-在当前元素上找到所需的控制器。如果找不到,则引发错误。

?-尝试找到所需的控制器,或者如果未找到,则将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.
}]);

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

如果您共享控制器,那么这样做总会更好:

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

在消费时:

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

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


4
而且这取决于控制器所提供的功能,如果要使其像需要在组件之间共享的视图模型那样,那很好,但是如果它具有更多的服务提供者功能,那么我将继续创建服务。
PSL 2014年

应该var testCtrl1ViewModel = $scope.$new();var testCtrl1ViewModel = $rootScope.$new();?请参阅:docs.angularjs.org/guide/controller @PSL
leonsPAPA 2015年

在上面的示例中,您正在访问指令控制器上的容器,但是我无法使其正常工作。我可以通过指令本身的链接函数上的第四个参数访问所需的控制器。但是它们并不像上面的示例那样绑定到指令控制器。还有谁有相同的问题吗?
Sammi

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();
}]);

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

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


13

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

<div ng-controller="TestCtrl1">
    <div ng-controller="TestCtrl2">
      <!-- your code--> 
    </div> 
</div>

2
是的,但是我仍然觉得最好将所有公共元素放入服务中并将服务注入到相应的控制器中。
Neel 2015年

-1
<div ng-controller="TestCtrl1">
    <div ng-controller="TestCtrl2">
      <!-- your code--> 
    </div> 
</div>

在我的情况下,这种方法效果最好,其中TestCtrl2有自己的指令。

var testCtrl2 = $controller('TestCtrl2')

这给我一个错误,指出scopeProvider注入错误。

   var testCtrl1ViewModel = $scope.$new();
   $controller('TestCtrl1',{$scope : testCtrl1ViewModel });
   testCtrl1ViewModel.myMethod(); 

如果您在'TestCtrl1'中有指令,则此操作实际上不起作用,该指令实际上具有与此处创建的指令不同的作用域。最后得到两个“ TestCtrl1”实例。


-1

最好的解决方案:

angular.module("myapp").controller("frstCtrl",function($scope){$scope.name="Atul Singh";}).controller("secondCtrl",function($scope){angular.extend(this, $controller('frstCtrl', {$scope:$scope}));console.log($scope);})

//在这里,您没有执行就得到了第一个控制器调用


-1

您还可以$rootScope像这样从第二个控制器调用第一个控制器的功能/方法,

.controller('ctrl1', function($rootScope, $scope) {
     $rootScope.methodOf2ndCtrl();
     //Your code here. 
})

.controller('ctrl2', function($rootScope, $scope) {
     $rootScope.methodOf2ndCtrl = function() {
     //Your code here. 
}
})

1
Downvote:这只是不好的编码:您只是在使函数全局化。如果这是您想要的编码方式,则最好完全删除Angular ...使用其他大多数答案所建议的服务。
HammerNL '16

不建议这样做。$ rootScope使代码笨拙并长期导致问题。
Harshit Pant

-2

使用typescript进行编码,因为它是面向对象的,严格输入并且易于维护代码...

有关typescipt的更多信息,请单击此处

这是我创建的一个简单示例,使用Typescript在两个控制器之间共享数据...

module Demo {
//create only one module for single Applicaiton
angular.module('app', []);
//Create a searvie to share the data
export class CommonService {
    sharedData: any;
    constructor() {
        this.sharedData = "send this data to Controller";
    }
}
//add Service to module app
angular.module('app').service('CommonService', CommonService);

//Create One controller for one purpose
export class FirstController {
    dataInCtrl1: any;
    //Don't forget to inject service to access data from service
    static $inject = ['CommonService']
    constructor(private commonService: CommonService) { }
    public getDataFromService() {
        this.dataInCtrl1 = this.commonService.sharedData;
    }
}
//add controller to module app
angular.module('app').controller('FirstController', FirstController);
export class SecondController {
    dataInCtrl2: any;
    static $inject = ['CommonService']
    constructor(private commonService: CommonService) { }
    public getDataFromService() {
        this.dataInCtrl2 = this.commonService.sharedData;
    }
}
angular.module('app').controller('SecondController', SecondController);

}

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.