我是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
我是否应该尝试在另一个控制器内使用控制器,还是应该将其作为服务?
答案 0 :(得分: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
确实是您的视图模型,在第二种情况下,它是控制器实例本身。
答案 1 :(得分: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();
}]);
答案 2 :(得分:13)
无需在JS中导入/注入您的控制器。您可以通过HTML注入您的控制器/嵌套控制器。它对我有用。 喜欢:
mysqldump -u root -ptest test_db > backup.sql
答案 3 :(得分:-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'实例。
答案 4 :(得分:-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);})
//这里你没有执行第一个控制器调用
答案 5 :(得分:-1)
您也可以使用$rootScope
从第二个控制器调用第一个控制器的功能/方法,
.controller('ctrl1', function($rootScope, $scope) {
$rootScope.methodOf2ndCtrl();
//Your code here.
})
.controller('ctrl2', function($rootScope, $scope) {
$rootScope.methodOf2ndCtrl = function() {
//Your code here.
}
})
答案 6 :(得分:-2)
使用typescript进行编码,因为它面向对象,严格打字并且易于维护代码......
有关typescipt click here
的更多信息这是我创建的一个简单示例,它使用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);
}