Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the recommended way to extend AngularJS controllers?

People also ask

Can we have two controllers in AngularJS?

Angular creates one $scope object for each controller. We also have a $rootScope accessible from every controllers.In case of multiple controllers AngularJS framework creates and pass a different $scope object to each controller so that data and methods of one controller not be accessed in another controller.

What are the controllers in AngularJS JS?

The controller in AngularJS is a JavaScript function that maintains the application data and behavior using $scope object. You can attach properties and methods to the $scope object inside a controller function, which in turn will add/update the data and attach behaviours to HTML elements.

Which is the correct syntax of creating AngularJS controller?

AngularJS Example The ng-controller="myCtrl" attribute is an AngularJS directive. It defines a controller. The myCtrl function is a JavaScript function. AngularJS will invoke the controller with a $scope object.

What is the use of angular extend?

Extends the destination object dst by copying own enumerable properties from the src object(s) to dst . You can specify multiple src objects. If you want to preserve original objects, you can do so by passing an empty object as the target: var object = angular. extend({}, object1, object2) .


Perhaps you don't extend a controller but it is possible to extend a controller or make a single controller a mixin of multiple controllers.

module.controller('CtrlImplAdvanced', ['$scope', '$controller', function ($scope, $controller) {
    // Initialize the super class and extend it.
    angular.extend(this, $controller('CtrlImpl', {$scope: $scope}));
    … Additional extensions to create a mixin.
}]);

When the parent controller is created the logic contained within it is also executed. See $controller() for for more information about but only the $scope value needs to be passed. All other values will be injected normally.

@mwarren, your concern is taken care of auto-magically by Angular dependency injection. All you need is to inject $scope, although you could override the other injected values if desired. Take the following example:

(function(angular) {

	var module = angular.module('stackoverflow.example',[]);

	module.controller('simpleController', function($scope, $document) {
		this.getOrigin = function() {
			return $document[0].location.origin;
		};
	});

	module.controller('complexController', function($scope, $controller) {
		angular.extend(this, $controller('simpleController', {$scope: $scope}));
	});

})(angular);
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.15/angular.js"></script>

<div ng-app="stackoverflow.example">
    <div ng-controller="complexController as C">
        <span><b>Origin from Controller:</b> {{C.getOrigin()}}</span>
    </div>
</div>

Although $document is not passed into 'simpleController' when it is created by 'complexController' $document is injected for us.


For inheritance you can use standard JavaScript inheritance patterns. Here is a demo which uses $injector

function Parent($scope) {
  $scope.name = 'Human';
  $scope.clickParent = function() {
    $scope.name = 'Clicked from base controller';
  }    
}

function Child($scope, $injector) {
  $injector.invoke(Parent, this, {$scope: $scope});
  $scope.name = 'Human Child';
  $scope.clickChild = function(){
    $scope.clickParent();
  }       
}

Child.prototype = Object.create(Parent.prototype);

In case you use the controllerAs syntax (which I highly recommend), it is even easier to use the classical inheritance pattern:

function BaseCtrl() {
  this.name = 'foobar';
}
BaseCtrl.prototype.parentMethod = function () {
  //body
};

function ChildCtrl() {
  BaseCtrl.call(this);
  this.name = 'baz';
}
ChildCtrl.prototype = Object.create(BaseCtrl.prototype);
ChildCtrl.prototype.childMethod = function () {
  this.parentMethod();
  //body
};

app.controller('BaseCtrl', BaseCtrl);
app.controller('ChildCtrl', ChildCtrl);

Another way could be to create just "abstract" constructor function which will be your base controller:

function BaseController() {
  this.click = function () {
    //some actions here
  };
}

module.controller('ChildCtrl', ['$scope', function ($scope) {
  BaseController.call($scope);
  $scope.anotherClick = function () {
    //other actions
  };
}]);

Blog post on this topic


Well, I'm not exactly sure what you want to achieve, but usually Services are the way to go. You can also use the Scope inheritance characteristics of Angular to share code between controllers:

<body ng-controller="ParentCtrl">
 <div ng-controller="FirstChildCtrl"></div>
 <div ng-controller="SecondChildCtrl"></div>
</body>

function ParentCtrl($scope) {
 $scope.fx = function() {
   alert("Hello World");
 });
}

function FirstChildCtrl($scope) {
  // $scope.fx() is available here
}

function SecondChildCtrl($scope) {
  // $scope.fx() is available here
}

You don't extend controllers. If they perform the same basic functions then those functions need to be moved to a service. That service can be injected into your controllers.


Yet another good solution taken from this article:

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

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

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

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

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

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

You can create a service and inherit its behaviour in any controller just by injecting it.

app.service("reusableCode", function() {

    var reusableCode = {};

    reusableCode.commonMethod = function() {
        alert('Hello, World!');
    };

    return reusableCode;
});

Then in your controller that you want to extend from the above reusableCode service:

app.controller('MainCtrl', function($scope, reusableCode) {

    angular.extend($scope, reusableCode);

    // now you can access all the properties of reusableCode in this $scope
    $scope.commonMethod()

});

DEMO PLUNKER: http://plnkr.co/edit/EQtj6I0X08xprE8D0n5b?p=preview


You can try something like this (have not tested):

function baseController(callback){
    return function($scope){
        $scope.baseMethod = function(){
            console.log('base method');
        }
        callback.apply(this, arguments);
    }
}

app.controller('childController', baseController(function(){

}));