AngularJS - A Better Way to Implement a Base Controller

There's quite a few different ways of implementing a base controller in AngularJS that people have posted about. Some use pure JavaScript prototypal inheritance while others do it with angular services/factories, however the cleanest and simplest way I've found is to use the AngularJS $controller service. 

Here's a cut down example from an application I'm working on at the moment, it contains controllers for adding and editing diary entries, and a base controller containing shared functionality.

AngularJS Base Controller

'use strict';

angular.module('Diary')

// base controller containing common functions for add/edit controllers
.controller('Diary.BaseAddEditController',
    ['$scope', 'DiaryService',
    function ($scope, DiaryService) {
        $scope.diaryEntry = {};

        $scope.saveDiaryEntry = function () {
            DiaryService.SaveDiaryEntry($scope.diaryEntry);
        };

        // add any other shared functionality here.
    }])

.controller('Diary.AddDiaryController',
    ['$scope', '$controller',
    function ($scope, $controller) {
        // instantiate base controller
        $controller('Diary.BaseAddEditController', { $scope: $scope });
    }])

.controller('Diary.EditDiaryController',
    ['$scope', '$routeParams', 'DiaryService', '$controller',
    function ($scope, $routeParams, DiaryService, $controller) {
        // instantiate base controller
        $controller('Diary.BaseAddEditController', { $scope: $scope });

        DiaryService.GetDiaryEntry($routeParams.id).success(function (data) {
            $scope.diaryEntry = data;
        });
    }]);

(See working on plunker at http://plnkr.co/edit/MfwS4w?p=preview)

It works by creating an instance of the base controller and injecting it with the child controller's $scope, making all the methods and properties added to the $scope by the base controller available in the child controller as well as the view. Although not technically inheritance in the 'classical programming' sense, it solves the issue of having duplicate code between controllers and quite elegantly in my opinion.

UPDATE 15 April 2016 - Added the below modified version that uses "controller as vm" syntax.

AngularJS Base Controller with "Controller as" Syntax

'use strict';

angular.module('Diary')
  .controller('Diary.BaseAddEditController', DiaryBaseAddEditController)
  .controller('Diary.AddController', DiaryAddController)
  .controller('Diary.EditController', DiaryEditController);

// Diary.BaseAddEditController
function DiaryBaseAddEditController(vm, DiaryService) {
	vm.diaryEntry = { name: 'default diary entry from Diary.BaseAddEditController' };

	vm.saveDiaryEntry = function () {
		DiaryService.SaveDiaryEntry(vm.diaryEntry);
	};

	// add any other shared functionality here.
}

// Diary.AddController
function DiaryAddController($controller) {
	var vm = this;

	// instantiate base controller
	$controller('Diary.BaseAddEditController', { vm: vm });
}

// Diary.EditController
function DiaryEditController($routeParams, DiaryService, $controller) {
	var vm = this;

	// instantiate base controller
	$controller('Diary.BaseAddEditController', { vm: vm });

	DiaryService.GetDiaryEntry($routeParams.id).success(function (data) {
		vm.diaryEntry = data;
	});
}

(See working on plunker at http://plnkr.co/edit/ZDvbhL?p=preview)

 

Web Development & AngularJS Consultant Sydney

Feel free to drop me a line if you're looking for a web development or AngularJS consultant in Sydney Australia, I also provide remote contracting services if you're outside Sydney.



blog comments powered by Disqus