Ich habe drei Controller, die ziemlich ähnlich sind. Ich möchte einen Controller haben, den diese drei erweitern und seine Funktionen teilen.
Ich habe drei Controller, die ziemlich ähnlich sind. Ich möchte einen Controller haben, den diese drei erweitern und seine Funktionen teilen.
Antworten:
Vielleicht erweitern Sie einen Controller nicht, aber es ist möglich, einen Controller zu erweitern oder einen einzelnen Controller zu einer Mischung aus mehreren Controllern zu machen.
module.controller('CtrlImplAdvanced', ['$scope', '$controller', function ($scope, $controller) {
// Initialize the super class and extend it.
angular.extend(this, $controller('CtrlImpl', {$scope: $scope}));
… Additional extensions to create a mixin.
}]);
Wenn der übergeordnete Controller erstellt wird, wird auch die darin enthaltene Logik ausgeführt. Weitere Informationen zu $ controller () finden Sie unter, aber nur der $scope
Wert muss übergeben werden. Alle anderen Werte werden normal injiziert.
@mwarren , Ihr Anliegen wird automatisch durch Angular Dependency Injection beseitigt . Alles, was Sie brauchen, ist $ scope zu injizieren, obwohl Sie die anderen injizierten Werte bei Bedarf überschreiben können. Nehmen Sie das folgende Beispiel:
(function(angular) {
var module = angular.module('stackoverflow.example',[]);
module.controller('simpleController', function($scope, $document) {
this.getOrigin = function() {
return $document[0].location.origin;
};
});
module.controller('complexController', function($scope, $controller) {
angular.extend(this, $controller('simpleController', {$scope: $scope}));
});
})(angular);
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.15/angular.js"></script>
<div ng-app="stackoverflow.example">
<div ng-controller="complexController as C">
<span><b>Origin from Controller:</b> {{C.getOrigin()}}</span>
</div>
</div>
Obwohl $ document nicht an 'simpleController' übergeben wird, wenn es von 'complexController' erstellt wird, wird $ document für uns injiziert.
$.extend()
, du kannst einfach anrufen$controller('CtrlImpl', {$scope: $scope});
angular.extend
(oder $.extend
) bedeutet eigentlich das Erweitern des $scope
einzigen, aber wenn Ihr Basis-Controller auch einige Eigenschaften definiert (z. B. this.myVar=5
), haben Sie nur Zugriff auf this.myVar
den erweiterten Controller, wenn Sieangular.extend
handleSubmitClick
welche würde anrufen, handleLogin
welche wiederum ein loginSuccess
und hatten loginFail
. Also, in meinem erweiterten Controller ich dann musste die zu überlasten handleSubmitClick
, handleLogin
und loginSucess
für die korrekte loginSuccess
Funktion zu nutzen.
Für die Vererbung können Sie Standard-JavaScript-Vererbungsmuster verwenden. Hier ist eine Demo, die verwendet$injector
function Parent($scope) {
$scope.name = 'Human';
$scope.clickParent = function() {
$scope.name = 'Clicked from base controller';
}
}
function Child($scope, $injector) {
$injector.invoke(Parent, this, {$scope: $scope});
$scope.name = 'Human Child';
$scope.clickChild = function(){
$scope.clickParent();
}
}
Child.prototype = Object.create(Parent.prototype);
Wenn Sie die controllerAs
Syntax verwenden (die ich sehr empfehle), ist es noch einfacher, das klassische Vererbungsmuster zu verwenden:
function BaseCtrl() {
this.name = 'foobar';
}
BaseCtrl.prototype.parentMethod = function () {
//body
};
function ChildCtrl() {
BaseCtrl.call(this);
this.name = 'baz';
}
ChildCtrl.prototype = Object.create(BaseCtrl.prototype);
ChildCtrl.prototype.childMethod = function () {
this.parentMethod();
//body
};
app.controller('BaseCtrl', BaseCtrl);
app.controller('ChildCtrl', ChildCtrl);
Eine andere Möglichkeit könnte darin bestehen, nur eine "abstrakte" Konstruktorfunktion zu erstellen, die Ihr Basis-Controller sein wird:
function BaseController() {
this.click = function () {
//some actions here
};
}
module.controller('ChildCtrl', ['$scope', function ($scope) {
BaseController.call($scope);
$scope.anotherClick = function () {
//other actions
};
}]);
Nun, ich bin mir nicht ganz sicher, was Sie erreichen möchten, aber normalerweise sind Services der richtige Weg. Sie können auch die Scope-Vererbungseigenschaften von Angular verwenden, um Code zwischen Controllern freizugeben:
<body ng-controller="ParentCtrl">
<div ng-controller="FirstChildCtrl"></div>
<div ng-controller="SecondChildCtrl"></div>
</body>
function ParentCtrl($scope) {
$scope.fx = function() {
alert("Hello World");
});
}
function FirstChildCtrl($scope) {
// $scope.fx() is available here
}
function SecondChildCtrl($scope) {
// $scope.fx() is available here
}
$scope.$parent.fx( )
viel sauberer, da es dort tatsächlich definiert ist?
Sie erweitern keine Controller. Wenn sie dieselben Grundfunktionen ausführen, müssen diese Funktionen in einen Dienst verschoben werden. Dieser Dienst kann in Ihre Controller eingespeist werden.
Noch eine gute Lösung aus diesem Artikel :
// base controller containing common functions for add/edit controllers
module.controller('Diary.BaseAddEditController', function ($scope, SomeService) {
$scope.diaryEntry = {};
$scope.saveDiaryEntry = function () {
SomeService.SaveDiaryEntry($scope.diaryEntry);
};
// add any other shared functionality here.
}])
module.controller('Diary.AddDiaryController', function ($scope, $controller) {
// instantiate base controller
$controller('Diary.BaseAddEditController', { $scope: $scope });
}])
module.controller('Diary.EditDiaryController', function ($scope, $routeParams, DiaryService, $controller) {
// instantiate base controller
$controller('Diary.BaseAddEditController', { $scope: $scope });
DiaryService.GetDiaryEntry($routeParams.id).success(function (data) {
$scope.diaryEntry = data;
});
}]);
Sie können einen Dienst erstellen und sein Verhalten in jedem Controller erben, indem Sie ihn einfach einfügen.
app.service("reusableCode", function() {
var reusableCode = {};
reusableCode.commonMethod = function() {
alert('Hello, World!');
};
return reusableCode;
});
Dann in Ihrem Controller, den Sie vom oben genannten reusableCode-Dienst erweitern möchten:
app.controller('MainCtrl', function($scope, reusableCode) {
angular.extend($scope, reusableCode);
// now you can access all the properties of reusableCode in this $scope
$scope.commonMethod()
});
DEMO PLUNKER: http://plnkr.co/edit/EQtj6I0X08xprE8D0n5b?p=preview
Sie können so etwas ausprobieren (noch nicht getestet):
function baseController(callback){
return function($scope){
$scope.baseMethod = function(){
console.log('base method');
}
callback.apply(this, arguments);
}
}
app.controller('childController', baseController(function(){
}));
Sie können mit einem Service , Fabriken oder Anbietern erweitern . Sie sind gleich, aber unterschiedlich flexibel.
Hier ein Beispiel mit Factory: http://jsfiddle.net/aaaflyvw/6KVtj/2/
angular.module('myApp',[])
.factory('myFactory', function() {
var myFactory = {
save: function () {
// saving ...
},
store: function () {
// storing ...
}
};
return myFactory;
})
.controller('myController', function($scope, myFactory) {
$scope.myFactory = myFactory;
myFactory.save(); // here you can use the save function
});
Und hier können Sie auch die Store-Funktion nutzen:
<div ng-controller="myController">
<input ng-blur="myFactory.store()" />
</div>
Sie können das Beispiel $ controller ('ParentController', {$ scope: $ scope}) direkt verwenden
module.controller('Parent', ['$scope', function ($scope) {
//code
}])
module.controller('CtrlImplAdvanced', ['$scope', '$controller', function ($scope, $controller) {
//extend parent controller
$controller('CtrlImpl', {$scope: $scope});
}]);
Sie können die Angular-Syntax "as" in Kombination mit einer einfachen JavaScript-Vererbung verwenden
Weitere Details finden Sie hier http://blogs.microsoft.co.il/oric/2015/01/01/base-controller-angularjs/
Ich habe eine Funktion geschrieben, um dies zu tun:
function extendController(baseController, extension) {
return [
'$scope', '$injector',
function($scope, $injector) {
$injector.invoke(baseController, this, { $scope: $scope });
$injector.invoke(extension, this, { $scope: $scope });
}
]
}
Sie können es so verwenden:
function() {
var BaseController = [
'$scope', '$http', // etc.
function($scope, $http, // etc.
$scope.myFunction = function() {
//
}
// etc.
}
];
app.controller('myController',
extendController(BaseController,
['$scope', '$filter', // etc.
function($scope, $filter /* etc. */)
$scope.myOtherFunction = function() {
//
}
// etc.
}]
)
);
}();
Vorteile:
Nachteile:
Ich betrachte die Erweiterung von Controllern als schlechte Praxis. Stellen Sie Ihre gemeinsame Logik lieber in einen Dienst. Erweiterte Objekte in Javascript werden in der Regel recht komplex. Wenn Sie die Vererbung verwenden möchten, würde ich Typoskript empfehlen. Trotzdem sind Thin Controller aus meiner Sicht der bessere Weg.