Benzer olan üç kontrolcüm var. Bu üçünün işlevlerini genişletip paylaştığı bir denetleyiciye sahip olmak istiyorum.
Benzer olan üç kontrolcüm var. Bu üçünün işlevlerini genişletip paylaştığı bir denetleyiciye sahip olmak istiyorum.
Yanıtlar:
Belki sen bir denetleyici uzatmaz ama bir denetleyici uzatmak veya tek bir kontrolör birden denetleyicilerin bir mixin yapmak mümkündür.
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.
}]);
Üst denetleyici oluşturulduğunda, içindeki mantık da yürütülür. Hakkında daha fazla bilgi için $ controller () işlevine bakın, ancak yalnızca $scope
değerin geçirilmesi gerekir. Diğer tüm değerler normal şekilde enjekte edilecektir.
mwarren , endişeniz açısal bağımlılık enjeksiyonu ile otomatik olarak halledilir. İhtiyacınız olan tek şey $ kapsamı enjekte etmek, ancak istenirse diğer enjekte edilen değerleri geçersiz kılabilirsiniz. Aşağıdaki örneği alın:
(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>
Her ne kadar 'complexController' tarafından yaratıldığında $ document 'simpleController' a aktarılmasa da, $ document bizim için enjekte edilir.
$.extend()
, sadece arayabilirsiniz$controller('CtrlImpl', {$scope: $scope});
angular.extend
(veya $.extend
) aslında $scope
sadece genişletmek anlamına gelir , ancak temel denetleyiciniz bazı özellikleri de tanımlıyorsa (örn. this.myVar=5
), yalnızca this.myVar
genişletme denetleyicisine erişiminiz olurangular.extend
handleSubmitClick
diyebiliriz . Yani, benim genişletilmiş denetleyicisi Sonra aşırı zorunda , ve doğru için işleve kullanılacak. handleLogin
loginSuccess
loginFail
handleSubmitClick
handleLogin
loginSucess
loginSuccess
Kalıtım için standart JavaScript kalıtım kalıplarını kullanabilirsiniz. İşte bir demo$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);
controllerAs
Sözdizimini kullanmanız durumunda (ki kesinlikle tavsiye ederim), klasik kalıtım modelini kullanmak daha da kolaydır:
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);
Başka bir yol, temel denetleyiciniz olacak sadece "soyut" yapıcı işlevi oluşturmak olabilir:
function BaseController() {
this.click = function () {
//some actions here
};
}
module.controller('ChildCtrl', ['$scope', function ($scope) {
BaseController.call($scope);
$scope.anotherClick = function () {
//other actions
};
}]);
Neyi başarmak istediğinizden tam olarak emin değilim, ancak genellikle Hizmetler gitmenin yolu. Denetleyicileri arasında kodu paylaşmak için Açısal'ın Kapsam miras özelliklerini de kullanabilirsiniz:
<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( )
gerçekte tanımlandığı yer olduğu için bunu yapmanın daha temiz bir yolu olmaz mıydı ?
Denetleyicileri genişletmezsiniz. Aynı temel işlevleri yerine getirirlerse, bu işlevlerin bir hizmete taşınması gerekir. Bu hizmet kontrolörlerinize enjekte edilebilir.
Bu makaleden alınan başka bir iyi çözüm :
// 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;
});
}]);
Herhangi bir denetleyicide bir hizmet oluşturabilir ve davranışını yalnızca enjekte ederek devralın.
app.service("reusableCode", function() {
var reusableCode = {};
reusableCode.commonMethod = function() {
alert('Hello, World!');
};
return reusableCode;
});
Daha sonra yukarıdaki reusableCode hizmetinden uzatmak istediğiniz kontrol cihazınızda:
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
Böyle bir şey deneyebilirsiniz (test etmediniz):
function baseController(callback){
return function($scope){
$scope.baseMethod = function(){
console.log('base method');
}
callback.apply(this, arguments);
}
}
app.controller('childController', baseController(function(){
}));
Bir hizmet , fabrika veya sağlayıcılarla genişletebilirsiniz . aynı ama farklı esneklik derecelerine sahipler.
Burada fabrika kullanan bir örnek: 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
});
Ve burada mağaza işlevini de kullanabilirsiniz:
<div ng-controller="myController">
<input ng-blur="myFactory.store()" />
</div>
Doğrudan $ controller ('ParentController', {$ scope: $ scope}) kullanabilirsiniz. Örnek
module.controller('Parent', ['$scope', function ($scope) {
//code
}])
module.controller('CtrlImplAdvanced', ['$scope', '$controller', function ($scope, $controller) {
//extend parent controller
$controller('CtrlImpl', {$scope: $scope});
}]);
Angular "as" sözdizimini düz JavaScript devralmasıyla birlikte kullanabilirsiniz
Daha fazla ayrıntı için buraya bakın http://blogs.microsoft.co.il/oric/2015/01/01/base-controller-angularjs/
Bunu yapmak için bir işlev yazdım:
function extendController(baseController, extension) {
return [
'$scope', '$injector',
function($scope, $injector) {
$injector.invoke(baseController, this, { $scope: $scope });
$injector.invoke(extension, this, { $scope: $scope });
}
]
}
Bu şekilde kullanabilirsiniz:
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.
}]
)
);
}();
Artıları:
Eksileri:
Denetleyicileri genişletmeyi kötü uygulama olarak görüyorum. Bunun yerine paylaşılan mantığınızı bir hizmete koyun. Javascript'teki genişletilmiş nesneler oldukça karmaşık olma eğilimindedir. Kalıtım kullanmak istiyorsanız, daktilo yazmanızı tavsiye ederim. Yine de, ince kontrolörler benim görüşüme göre daha iyi bir yol.