AngularJS 控制器可以从同一模块中的另一个控制器继承吗?
Posted
技术标签:
【中文标题】AngularJS 控制器可以从同一模块中的另一个控制器继承吗?【英文标题】:Can an AngularJS controller inherit from another controller in the same module? 【发布时间】:2013-08-29 22:54:09 【问题描述】:在模块内,控制器可以从外部控制器继承属性:
var app = angular.module('angularjs-starter', []);
var ParentCtrl = function ($scope, $location)
;
app.controller('ChildCtrl', function($scope, $injector)
$injector.invoke(ParentCtrl, this, $scope: $scope);
);
示例来自:死链接:http://blog.omkarpatil.com/2013/02/controller-inheritance-in-angularjs.html
模块内的控制器也可以从兄弟继承吗?
var app = angular.module('angularjs-starter', []);
app.controller('ParentCtrl ', function($scope)
//I'm the sibling, but want to act as parent
);
app.controller('ChildCtrl', function($scope, $injector)
$injector.invoke(ParentCtrl, this, $scope: $scope); //This does not work
);
第二个代码不起作用,因为$injector.invoke
需要一个函数作为第一个参数并且找不到对ParentCtrl
的引用。
【问题讨论】:
这应该会有所帮助:***.com/questions/16828287/… aside:这看起来不像继承,更像是共享方法或注入。也许只是语义。 该示例的链接不再有效。 Google 缓存链接:webcache.googleusercontent.com/… 指向这个有趣的 Fiddle:jsfiddle.net/mhevery/u6s88/12 【参考方案1】:是的,可以,但您必须使用$controller
服务来实例化控制器:-
var app = angular.module('angularjs-starter', []);
app.controller('ParentCtrl', function($scope)
// I'm the sibling, but want to act as parent
);
app.controller('ChildCtrl', function($scope, $controller)
$controller('ParentCtrl', $scope: $scope); //This works
);
【讨论】:
ParentCtrl
应该是 controller
还是可以使用 service
?
@gontard:在这种情况下它必须是一个控制器,因为$controller
只能使用注册的控制器。
这是一个非常好的解决方案。谢谢你。但是如果我使用 Controller As 语法,我该怎么做呢?
上述小提琴是作为一个问题提出的。值得注意的是,controllerAs 只是将控制器分配给范围 - 所以你可以将 $scope
更改为 this
(理论上)
这对我有用,但是我正在尝试以一种方式将父控制器和子控制器放在同一页面上。这会导致父控制器中的 $http 操作运行两次。当子控制器注入父控制器的范围时,我的 $scope.AllMembers 数组被填充两次,因为父控制器使其运行,然后子控制器使其再次运行。有什么办法可以防止吗?【参考方案2】:
如果您使用vm
controller syntax,这是我的解决方案:
.controller("BaseGenericCtrl", function ($scope)
var vm = this;
vm.reload = reload;
vm.items = [];
function reload()
// this function will come from child controller scope - RESTDataService.getItemsA
this.getItems();
)
.controller("ChildCtrl", function ($scope, $controller, RESTDataService)
var vm = this;
vm.getItems = RESTDataService.getItemsA;
angular.extend(vm, $controller('BaseGenericCtrl', $scope: $scope));
)
不幸的是,您不能使用$controller.call(vm, 'BaseGenericCtrl'...)
将当前上下文传递给闭包(对于reload()
)函数,因此只有一种解决方案是在继承函数中使用this
以动态更改上下文。
【讨论】:
你就不能这样做吗? > $controller('BaseGenericControl', vm: vm );vm
只是控制器内部的一个变量,我不认为 Angular 可以按预期使用它。【参考方案3】:
我认为,您应该使用工厂或服务,为两个控制器提供可访问的功能或数据。
这里有类似的问题 ---> AngularJS controller inheritance
【讨论】:
是的,这是一种方法,谢谢。我在寻找解决方案时遇到了那个帖子。我在想是否有某种方法可以加载控制器功能并用它扩展“this”。 我想要一个通用的loading
变量,以便在加载数据时我总是做同样的事情,我认为工厂做不到。我的父控制器可以有一个加载变量,但工厂不能操纵它......对吧?!【参考方案4】:
针对this answer by gmontague 中提出的问题,我找到了一种使用$controller() 继承控制器的方法,并且仍然使用控制器“as”语法。
首先,在继承调用 $controller() 时使用“as”语法:
app.controller('ParentCtrl', function(etc...)
this.foo = 'bar';
);
app.controller('ChildCtrl', function($scope, $controller, etc...)
var ctrl = $controller('ParentCtrl as parent', etc: etc, ...);
angular.extend(this, ctrl);
);
然后,在 HTML 模板中,如果属性是由 parent 定义的,则使用parent.
检索从 parent 继承的属性;如果由孩子定义,则使用child.
检索它。
<div ng-controller="ChildCtrl as child"> parent.foo </div>
【讨论】:
【参考方案5】:好吧,我以另一种方式做到了这一点。就我而言,我想要一个在其他控制器中应用相同功能和属性的功能。我喜欢它,除了参数。这样,你所有的 ChildCtrl 都需要接收 $location。
var app = angular.module('angularjs-starter', []);
function BaseCtrl ($scope, $location)
$scope.myProp = 'Foo';
$scope.myMethod = function bar() /* do magic */ ;
app.controller('ChildCtrl', function($scope, $location)
BaseCtrl.call(this, $scope, $location);
// it works
$scope.myMethod();
);
【讨论】:
【参考方案6】:对于那些想知道的人,您可以使用已接受答案中的方法以相同的方式扩展组件控制器。
使用以下方法:
父组件(扩展自):
/**
* Module definition and dependencies
*/
angular.module('App.Parent', [])
/**
* Component
*/
.component('parent',
templateUrl: 'parent.html',
controller: 'ParentCtrl',
)
/**
* Controller
*/
.controller('ParentCtrl', function($parentDep)
//Get controller
const $ctrl = this;
/**
* On init
*/
this.$onInit = function()
//Do stuff
this.something = true;
;
);
子组件(扩展的那个):
/**
* Module definition and dependencies
*/
angular.module('App.Child', [])
/**
* Component
*/
.component('child',
templateUrl: 'child.html',
controller: 'ChildCtrl',
)
/**
* Controller
*/
.controller('ChildCtrl', function($controller)
//Get controllers
const $ctrl = this;
const $base = $controller('ParentCtrl', );
//NOTE: no need to pass $parentDep in here, it is resolved automatically
//if it's a global service/dependency
//Extend
angular.extend($ctrl, $base);
/**
* On init
*/
this.$onInit = function()
//Call parent init
$base.$onInit.call(this);
//Do other stuff
this.somethingElse = true;
;
);
诀窍是使用命名控制器,而不是在组件定义中定义它们。
【讨论】:
【参考方案7】:如已接受的答案中所述,您可以通过在您的子控制器中调用:$controller('ParentCtrl', $scope: $scope, etc: etc);
“继承”父控制器对 $scope 和其他服务的修改。
但是,如果您习惯于使用控制器的“as”语法,例如在
<div ng-controller="ChildCtrl as child"> child.foo </div>
如果在父控制器中设置了foo
(通过this.foo = ...
),子控制器将无权访问它。
如 cmets 中所述,您可以将 $controller 的结果直接分配给作用域:
var app = angular.module('angularjs-starter', []);
app.controller('ParentCtrl ', function(etc...)
this.foo = 'bar';
);
app.controller('ChildCtrl', function($scope, $controller, etc...)
var inst = $controller('ParentCtrl', etc: etc, ...);
// Perform extensions to inst
inst.baz = inst.foo + " extended";
// Attach to the scope
$scope.child = inst;
);
注意:然后您必须从ng-controller=
中删除“as”部分,因为您在代码中指定实例名称,而不是模板。
【讨论】:
使用“controller as”语法没有问题。看我的回答:***.com/a/36549465/2197555【参考方案8】:我在vm = this
中使用“Controller as”语法并想继承一个控制器。如果我的父控制器有一个修改变量的函数,我会遇到问题。
使用 IProblemFactory's 和 Salman Abbas's 答案,我做了以下操作来访问父变量:
(function ()
'use strict';
angular
.module('MyApp',[])
.controller('AbstractController', AbstractController)
.controller('ChildController', ChildController);
function AbstractController(child)
var vm = child;
vm.foo = 0;
vm.addToFoo = function()
vm.foo+=1;
;
function ChildController($controller)
var vm = this;
angular.extend(vm, $controller('AbstractController', child: vm));
;
)();
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-controller="ChildController as childCtrl" layout="column" ng-cloak="" ng-app="MyApp">
<button type="button" ng-click="childCtrl.addToFoo()">
add
</button>
<span>
-- childCtrl.foo --
</span>
</div>
【讨论】:
【参考方案9】:您可以使用简单的 javascript 继承机制。也不要忘记传递一个必要的角度服务来调用 .call 方法。
//simple function (js class)
function baseCtrl($http, $scope, $location, $rootScope, $routeParams, $log, $timeout, $window, modalService) //any serrvices and your 2
this.id = $routeParams.id;
$scope.id = this.id;
this.someFunc = function()
$http.get("url?id="+this.id)
.then(success function(response)
....
)
...
angular
.module('app')
.controller('childCtrl', childCtrl);
//angular controller function
function childCtrl($http, $scope, $location, $rootScope, $routeParams, $log, $timeout, $window, modalService)
var ctrl = this;
baseCtrl.call(this, $http, $scope, $location, $rootScope, $routeParams, $log, $timeout, $window, modalService);
var idCopy = ctrl.id;
if($scope.id == ctrl.id)//just for sample
ctrl.someFunc();
//also you can copy prototype of the base controller
childCtrl.prototype = Object.create(baseCtrl.prototype);
【讨论】:
以上是关于AngularJS 控制器可以从同一模块中的另一个控制器继承吗?的主要内容,如果未能解决你的问题,请参考以下文章
如何从AngularJS中的另一个控制器调用函数? [复制]