如何将控制器注入到AngularJS的另一个控制器中
我是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
我是否应该尝试在另一个控制器内使用控制器,还是应该使用这个服务?
如果你的意图是要获得另一个组件的已经实例化的控制器,并且如果你遵循基于组件/指令的方法,你可以总是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 ie 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>
有很多方法可以设置要求 。
(无前缀) – 在当前元素上find所需的控制器。 抛出一个错误,如果没有find。
? – 尝试find所需的控制器或将null传递给链接fn(如果找不到)。
^ – 通过search元素及其父母find所需的控制器。 抛出一个错误,如果没有find。
^^ – 通过search元素的父母find所需的控制器。 抛出一个错误,如果没有find。
?^ – 尝试通过search元素及其父项来查找所需的控制器,或者如果未find,则将null传递给链接fn。
?^^ – 尝试通过search元素的父项来定位所需的控制器,或者如果未find,则将null传递给链接fn。
老答案:
您需要注入$controller
服务来实例化另一个控制器内的控制器。 但请注意,这可能会导致一些devise问题。 您可以随时创build遵循单一责任的可重用服务,并根据需要将其注入到控制器中。
例:
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
是您的视图模型,而第二种情况下是控制器实例本身。
我build议你应该问的问题是如何注入服务到控制器。 脂肪服务与瘦身控制器是一个很好的经验法则,也就是使用控制器粘贴您的服务/工厂(与业务逻辑)到您的意见。
控制器在路由更改时收集垃圾,例如,如果您使用控制器来保存呈现值的业务逻辑,那么如果应用程序用户单击浏览器后退button,则会在两个页面上丢失状态。
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(); }]);
这里是工厂注入两个控制器的工作演示
另外,我build议阅读本教程的服务/工厂。
没有必要在JS中导入/注入你的控制器。 你可以通过你的HTML注入你的控制器/嵌套控制器。它适用于我。 喜欢 :
<div ng-controller="TestCtrl1"> <div ng-controller="TestCtrl2"> <!-- your code--> </div> </div>
<div ng-controller="TestCtrl1"> <div ng-controller="TestCtrl2"> <!-- your code--> </div> </div>
这在我的情况下效果最好,TestCtrl2有它自己的指令。
var testCtrl2 = $controller('TestCtrl2')
这给我一个错误,说范围提供者注入错误。
var testCtrl1ViewModel = $scope.$new(); $controller('TestCtrl1',{$scope : testCtrl1ViewModel }); testCtrl1ViewModel.myMethod();
如果你在'TestCtrl1'中有指令,这个指令实际上不起作用,这个指令实际上与这里创build的指令有不同的作用域。 您最终有两个“TestCtrl1”的实例。
最好的解决scheme:
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);})
//这里你没有执行第一个控制器调用
你也可以使用$rootScope
像这样从第二个控制器调用第一个控制器的函数/方法,
.controller('ctrl1', function($rootScope, $scope) { $rootScope.methodOf2ndCtrl(); //Your code here. }) .controller('ctrl2', function($rootScope, $scope) { $rootScope.methodOf2ndCtrl = function() { //Your code here. } })
使用打字稿为您的编码,因为它是面向对象的,严格键入和易于维护代码…
有关typescipt的更多信息, 请点击这里
这里我创build了一个简单的例子来使用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);
}