I have been working on AngularJS for a while and have researched quite a lot. I am working on building reusable custom components/widgets using AngularJS directives. I have been quite successful at it. However, I want to adhere to inheritance while doing the same. Let me explain with an example.
I have created a directive myButton
that creates a button with all the styles & functionality. Now I would like to extend/inherit this myButton
to create a myToggleButton
with some added features & functionality. I do not wish to rewrite myButton
features again.
I have explored various options.
As suggested in https://gist.github.com/BrainCrumbz/5832057, I created a factory/service and injected it into the directive. But this is not allowing me to take full benefit of the inheritance. I am still having to rewrite most of the properties.
I tried using plain object-oriented JavaScript for inheritance but in that case I would not be using AngulrJS directives. I want to follow Angular concepts strictly.
So any suggestions would be most welcome.
I have also found most inheritance examples less than ideal but I have come up with a solution I think is clean and allows for fully inheritance.
As services and directives do not have prototype information available in them and extending Object directly is not good you will want to create a high level base class which could contain constants or very simple generic logic.
var BaseService = function() {};
BaseService.prototype.toast = "french";
BaseService.prototype.halloween = "scary";
Next lets create an abstract service (same logic for a directive) that can be extended.
module.factory('AbstractDirective', function(
$http, $q, $rootScope, $compile, $timeout) {
$.extend(this, new BaseService);
// Additional logic and methods should be appended onto 'this'
this.doStuff = function() {
alert("abstract function called");
};
this.halloween = 'fun';
// If adding a variable to the prototype of this extended class is desired
// then this function would need to be extracted to its own variable
// where the prototype values can be set before the function
// is passed to the factory.
return this;
}
Now lets create an actual implementation:
module.directive('DirectiveImpl', ['AbstractDirective', function(AbstractDirective) {
$.extend(this, AbstractDirective);
// A great part about this implementation pattern is that
// DirectiveImpl does not need to pass anything to construct AbstractDirective.
// Meaning changes to AbstractDirective will have less impacts
// on implementing classes.
this.doStuff = function () {
// Call
AbstractDirective.doStuff();
// Implement some logic additional
alert(this.toast + "Toast\nHalloween is " + this.halloween );
}
return this;
}]);
for services use
module.factory
instead of
module.directive
When the doStuff function is call for DirectiveImpl you will get 2 alerts:
abstract function called
then
French Toast
Halloween is fun
A similar pattern can be followed to allow full inheritance for controllers as well but there is a bit more to get that to work.
I used this implementation (based on Enzey's model) to get my directive to work as intended.
module.directive('DirectiveImpl', ['AbstractDirective', function(AbstractDirective) {
return {
controller: ['$scope','$element', function( $scope, $element ) {
$.extend($scope, AbstractDirective);
// A great part about this implementation pattern is that
// DirectiveImpl does not need to pass anything to construct
// AbstractDirective.
// Meaning changes to AbstractDirective will have less impacts
// on implementing classes.
$scope.doStuff = function () {
// Call
AbstractDirective.doStuff();
// Implement some logic additional
alert($scope.toast + "Toast\nHalloween is " + $scope.halloween );
}
},
link: function( scope, element, opts ) {
scope.doStuff();
}
}
}]);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With