When building complex Angular applications with multiple controllers, you may find yourself in a situation where two or more controllers perform similar tasks, but are slightly different. A good way to minimize code duplication is to create a base controller and extend it’s behavior in other controllers. Here’s a simple example to see how this works.
Controllers
Let’s start by defining two separate controllers - SimpleCalculatorCtrl
and AdvancedCalculatorCtrl
.
angular
.module("myAwesomeApp", [])
.controller("SimpleCalculatorCtrl", function() {
var vm = this;
vm.add = add;
vm.subtract = subtract;
function add(a, b) {
vm.result = a + b;
}
function subtract(a, b) {
vm.result = a - b;
}
});
.controller("AdvancedCalculatorCtrl", function() {
var vm = this;
vm.add = add;
vm.subtract = subtract;
vm.multiply = multiply;
vm.divide = divide;
function add(a, b) {
vm.result = a + b;
}
function subtract(a, b) {
vm.result = a - b;
}
function multiply(a,b) {
vm.result = a * b;
}
function divide(a, b) {
vm.result = a / b;
}
});
Now lets put our new controllers to use:
<html>
<body>
<div ng-controller="SimpleCalculatorCtrl as sc">
Result: <span ng-bind="sc.result"></span>
<input ng-model="sc.a"></input>
<input ng-model="sc.b"></input>
<button ng-click="sc.add(sc.a, sc.b)">
Add
</button>
<button ng-click="sc.subtract(sc.a, sc.b)">
Subtract
</button>
</div>
<div ng-controller="AdvancedCalculatorCtrl as ac">
Result: <span ng-bind="ac.result"></span>
<input ng-model="ac.a"></input>
<input ng-model="ac.b"></input>
<button ng-click="ac.add(ac.a, ac.b)">
Add
</button>
<button ng-click="ac.subtract(ac.a, ac.b)">
Subtract
</button>
<button ng-click="ac.multiply(ac.a, ac.b)">
Multiply
</button>
<button ng-click="ac.divide(ac.a, ac.b)">
Divide
</button>
</div>
</body>
</html>
SimpleCalculator
and AdvancedCalculator
both contain identical add
and delete
functions, but AdvancedCalculator
also contains functionality for multiply
and divide
. Now one way to simplify both controllers is creating a CalculatorService
which takes care of the actual logic for us; but there’s more to it, since both controllers also need to update the result
and display it’s new value on the DOM.
Creating a Base Controller
Let’s create a base controller for our calculator controllers. Our base controller will contain all of the functionality that is shared between SimpleCalculator
and AdvancedCalculator
.
angular
.module("myAwesomeApp", [])
.controller("CalculatorCtrl", function() {
var vm = this;
vm.add = add;
vm.subtract = subtract;
vm.data = {};
function add(a, b) {
vm.data.result = a + b;
}
function subtract(a, b) {
vm.data.result = a - b;
}
});
Extending the Base Controller
Now we can simplify our SimpleCalculatorCtrl
and AdvancedCalculatorCtrl
like so:
angular
.module("myAwesomeApp", [])
.controller("SimpleCalculatorCtrl", function($scope, $controller) {
var vm = this;
// Inherit from Base Controller
angular.extend(vm, $controller('CalculatorCtrl', {
$scope: $scope
}));
})
.controller("AdvancedCalculatorCtrl", function($scope, $controller) {
var vm = this;
// Inherit from Base Controller
angular.extend(vm, $controller('CalculatorCtrl', {
$scope: $scope
}));
vm.multiply = multiply;
vm.divide = divide;
function multiply(a,b) {
vm.data.result = a * b;
}
function divide(a, b) {
vm.data.result = a / b;
}
});
As you can see, we’ve removed duplicate code from both of our controllers by extending our base controller - CalculatorCtrl
. We do this by injecting Angular’s built in $controller
service to initialize our base controller, and then use angular.extend
to extend our current controller with our base controller.
We moved the result
property originally on our controller into an empty Object
called data
. This is because in JavaScript changing the value of a variable never changes the underlying Object
itself; however changing the property of an Object
referenced by a variable does change the underlying Object
. Therefore any properties that we would like to share between two controllers must be kept on a parent Object
.
Remember that in this particular case it may make sense to just create a single controller and re-using it as needed. However, as the number of controllers in your application grow and become more complex, the ability to extend a controller becomes very useful.