AngularJS 控制器可以继承同一模块中的另一个控制器吗?

在一个模块中,控制器可以从外部控制器继承属性:

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 < a href = " 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的引用。

90253 次浏览

我认为,你应该使用工厂或服务,为两个控制器提供可访问的功能或数据。

这里有一个类似的问题——> AngularJS控制器继承

是的,它可以,但你必须使用$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
});

正如在接受的答案中提到的,你可以通过在你的子控制器中调用:$controller('ParentCtrl', {$scope: $scope, etc: etc});来“继承”父控制器对$scope和其他服务的修改。

然而,如果你习惯使用控制器“as”语法,则会失败,例如在

<div ng-controller="ChildCtrl as child">\{\{ child.foo }}</div>

如果在父控制器中设置了foo(通过this.foo = ...),子控制器将无法访问它。

正如注释中提到的,你可以将$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'部分,因为你在代码中指定实例名,而不再是模板。

我用了另一种方法。在我的例子中,我想要一个在其他控制器中应用相同函数和属性的函数。我喜欢它,除了一些参数。通过这种方式,所有的ChildCtrls都需要接收$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();
});

如果你正在使用vm控制器语法,这是我的解决方案:

.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()继承控制器的方法,并且仍然使用控制器“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.来检索从父属性继承的属性;如果由child定义,则使用child.来检索它。

    <div ng-controller="ChildCtrl as child">\{\{ parent.foo }}</div>

我在vm = this中使用了“Controller as”语法,并希望继承一个控制器。如果我的父控制器有一个修改变量的函数,我就会有问题。

使用IProblemFactory的萨尔曼·阿巴斯的的答案,我做了以下操作来访问父变量:

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

对于那些想知道的人,您可以以同样的方式扩展组件控制器,使用已接受答案中的方法。

请使用以下方法:

父组件(从):

/**
* 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;
};
});

诀窍在于使用命名控制器,而不是在组件定义中定义它们。

您可以使用简单的JavaScript继承机制。另外,不要忘记传递一个必要的angular服务调用的.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);