First, lets talk about controllers. Actually it is very unlikely to inherit from parent controller (except when you’re using the controller as syntax, see below). This is the case because by implementation the scope in the child controller will inherit prototypically from its parent scope. So when you need to reuse functionality from the parent controller, all you need to do is add the required methods to the parent scope. By doing this the child controller will have access to all these methods through the prototype of its scope i.e.:
Of course, the inheritance creates very strong coupling but only in a single direction (i.e. the child is strongly coupled to its parent), so you can’t directly call children methods from your parent controller. For doing this you need to use event dispatching:
I’m providing this snippet with only informative purpose, if you need to call children methods from your parent controller, you might be doing something wrong.
OK, but now let’s imagine you have two pages with almost the same functionality, lets say the intersection between the functionality of the pages is more than 50%. They might have totally different views but the logic behind these views could be quite similar. In such case you can create a base controller which encapsulates the common logic, and two children controllers which inherit from it. The base controller is not necessary to be implemented as AngularJS controller component you can use simple constructor function:
Now the children controllers can easily inherit from the base controller by:
As you can see we directly apply the “Klassical” inheritance pattern. We can do the same for the second child controller. You can check example right here.
Controller as syntax
AngularJS 1.2 added the controller as syntax. Basically it allows us to create aliases for our controllers, for example using the
ng-controller directive we can:
with the following controller:
which can be used with the following markup:
When the user press the button with label “Invoke parent” the
parentMethod defined in
BaseCtrl will be invoked. If the user press “Invoke child” the
childMethod will be invoked. Notice that in its body it invokes
parentMethod as well.
As you know there are two ways to create injectable (through DI) AngularJS services:
- module.factory(name, factoryFn)
- module.service(name, factoryFn)
factoryFn returns object literal which is the actual service. Behind the scene AngularJS calls the
factory function inside the injector definition
If you need inheritance in services which are instantiated through
module.factory the prototype inheritance pattern through
Object.create fits just great!
Lets create the base service:
and here is the child service:
Now you can inject
ChildService in different component and reuse the inherited from
You can find an example right here.
Inject the parent
One more pattern for inheritance with services is injecting the parent through dependency injection and creating new object, which inherits from the parent prototypically:
This pattern is definitely much more useful when you need to inject some dependencies to the parent service before inheriting it.
Usually I call the variables attached to my scope View Models and the special services, which encapsulate the business logic – Models. I implement these services with something close to the Active Record Pattern. My models are usually responsible for talking to the server, sometimes directly but usually through a Gateway. For the creation of these models I prefer to use
module.service method. Internally these services are created through the
Why I prefer using service instead of factory? Well, may be I’m a confused developer who doesn’t understand the true power of the prototypal inheritance used with object literals, however I prefer to use the classical one for my models. By using it I can create a set of constructor functions which model my domain pretty well. One day I may decide to use MDD and generate all my models from some fancy UML diagrams…
Here is an example of how you can take advantage of the Klassical inheritance pattern for AngularJS services created with
Here is a talk on this topic I gave on Angular Berlin: