Question
AngularJS + OOP is kinda sexy feature to use
Hi, I'm successfully using OOP with AngularJs for some time already (first started with [angularjs with oop inheritance in action](https://stackoverflow.com/questions/17389291/angularjs-with-oop- inheritance-in-action)), the provided approach allows you define your classes as angular services, which you can later extend or inherit from like that:
Application.factory('AbstractObject', [function () {
var AbstractObject = Class.extend({
virtualMethod: function() {
alert("Hello world");
},
abstractMethod: function() { // You may omit abstract definitions, but they make your interface more readable
throw new Error("Pure abstract call");
}
});
return AbstractObject; // You return class definition instead of it's instance
}]);
Application.factory('DerivedObject', ['AbstractObject', function (AbstractObject) {
var DerivedObject = AbstractObject.extend({
virtualMethod: function() { // Shows two alerts: `Hey!` and `Hello world`
alert("Hey!");
this._super();
},
abstractMethod: function() {
alert("Now I'm not abstract");
}
});
return DerivedObject;
}]);
Plunker: http://plnkr.co/edit/rAtVGAsNYggBhNADMeoT
using the described approach gives you the ability to define classes that beautifully integrate into angular infrastructure. You get all sort of nifty features from two worlds - OOP and AngularJs. Dependency injection is free for your classes, and it makes your classes simple, allows putting a lot of boilerplate controller code into some base class that can be later reused.
However
AngularJs infrastructure blocks previously described approach from spreading
it's wings on all 100%. The problem occurs when you try to define recursive
class definitions (i.e. recursive aggregation), say you have two class
definitions like Blog
and Tag
Application.factory('Blog', ['Tag', function (Tag) {
var Blog = Class.extend({
tags: function() {
return this.tags;
}
});
return Blog;
}]);
Application.factory('Tag', ['Blog', function (Blog) {
var Tag = Class.extend({
Blogs: function() {
return this.blogs;
}
});
return Tag;
}]);
It won't work because both Blog
and Tag
are self-referencing themselves
causing circular dependency.
P.S
The last thing, I have found kinda ugly solution that solves my problem in my specific case but doesn't work in general and as I said, it isn't pretty:
Application.factory('BlogNamespace', [function () {
var Blog = Class.extend({
tags: function() {
return this.tags;
}
});
var Tag = Class.extend({
Blogs: function() {
return this.blogs;
}
});
return {
Tag: Tag,
Blog: Blog
};
}]);
Question
The above fix won't work because namespaces may also be a subject of circular dependency. This means that it isn't solution to described problem but rather one level deeper problem now.
Any suggestions on how it is possible to solve described problem in general case?
Answer
A circular dependency is always the sign of mixing of concerns , which is a really bad thing. Miško Hevery, one of the authors of AngularJS, explains a nice solution [on his awesome blog](http://misko.hevery.com/2008/08/01/circular-dependency-in-constructors- and-dependency-injection/). In short, you probably have a third service hidden somewhere, which is the only part of your code really needed by the two others.