26

I have defined one controller, and apply it to 2 views with small differences.

Angular code:

app.controller('MyCtrl', function($scope) {
   $scope.canSave = false;
   $scope.demo = {
      files : [{
         filename: 'aaa.html',
         source: '<div>aaa</div>'
      }, {
         filename: 'bbb.html',
         source: '<div>bbb</div>'
      }]
   }
   $scope.newFile = function(file) {
       $scope.demo.files.push(file);
   }
   $scope.$watch("demo.files", function(val) {
       $scope.canSave = true;
   }, true);
});

View 1:

<div ng-controller="MyCtrl"></div>

View 2:

<div ng-controller="MyCtrl"></div>

The sample code is very simple, but there are a lot of code and logic in my real project.

The View 1 and 2 have almost the same features, only with a few differences, but I do need to write some code for each of them in the controller.

I don't want to create 2 different controllers for them, because they have most of same logic. I don't want to move the logic to a service to share it between the 2 controllers, because the logic is not that common to be a service.

Is there any other way to do it?

Freewind
  • 193,756
  • 157
  • 432
  • 708
  • So just put everything you need for both views in that one controller and you're ready to go... – holographic-principle Mar 25 '13 at 15:38
  • 1
    The logic need not be used anywhere and everywhere to move it to a service. A service needs to be the place where most of your logic should go, whether its shared or not. – ganaraj Mar 25 '13 at 15:46

4 Answers4

18

Under the given conditions I might be doing something like

function MyCommonCtrl(type){
    return function($scope, $http) {
        $scope.x = 5;

        if(type = 't1'){
            $scope.domore = function(){
            }
        }

        ....
        ....
    }
}

angular.module('ng').controller('Type1Ctrl', ['$scope', '$http', MyCommonCtrl('t1')]);
angular.module('ng').controller('Type2Ctrl', ['$scope', '$http', MyCommonCtrl('t2')]);

Then

<div ng-controller="Type1Ctrl"></div>

and

<div ng-controller="Type2Ctrl"></div>
Arun P Johny
  • 384,651
  • 66
  • 527
  • 531
  • 1
    To me this looks way more like a hack but like a solution. Hence -1. I like the clean solution using inheritance suggested by @axzr way better. – Golo Roden Mar 26 '13 at 09:18
  • 1
    This is indeed a bad solution I think. – fdomig Jul 03 '13 at 15:12
  • 3
    I like this solution - a true function-slinging traditional javascript approach, with few if any drawbacks. Completely testable, flexible and easy to understand. Inheritance is much more likely to give you headaches down the road because of its less obvious workings and added complexity w/r to own and inherited properties. – Magnus Wolffelt Jan 03 '14 at 16:02
  • I agree with Magnus. Inheritance in JS is best avoided. – Lucidity Feb 27 '15 at 15:22
  • 1
    This is a great solution. Maybe rename your MyCommonCtrl to CreateController as it is more like a factory. You can also apply all object generation patterns to construct reusable controllers. – Thomas Apr 19 '17 at 11:22
  • @Thomas: +1 for suggesting to rename the function. However, can you elaborate on what you mean by "apply all object generation patterns"? Thanks. – user1438038 Jun 03 '21 at 13:19
6

I don't know your specific set-up but your 2 controllers could inherit from a common ancestor.

Type1Ctrl.prototype = new MyCtrl();
Type1Ctrl.prototype.constructor = Type1Ctrl;

function Type1Ctrl() {
  // constructor stuff goes here
}

Type1Ctrl.prototype.setScope = function() {
  // setScope
};

Type2Ctrl.prototype = new MyCtrl();
Type2Ctrl.prototype.constructor = Type2Ctrl;

function Type2Ctrl() {
  // constructor stuff goes here
}

Type2Ctrl.prototype.setScope = function() {
  // setScope
};
axzr
  • 660
  • 5
  • 16
  • I've never write controllers like this, could you give me some more information about it? – Freewind Mar 26 '13 at 12:59
  • @Freewind: sure. Could you post a bit more logic from your existing controllers and I can help you shape them to use inheritance? Either that or just do some reading up on inheritance in Javascript. – axzr Mar 26 '13 at 19:09
  • @Freewind: for me to help you further it would be really useful if you show me how your controller varies by view. Are you doing anything at the moment to change its behaviour based on the view or are you still planning for that? – axzr Mar 27 '13 at 08:44
3

I also faced similar problem and scope inheritance solved my problem. I wanted to "reuse" a controller to inherit common state/model ($scope) and functionality (controller functions attached to $scope) As described in the "Scope Inheritance Example" I attach parent controller to an outer DOM element and child controller to the inner. Scope and functions of parent controller "merge" seamlessly into the child one.

Sergey Shcherbakov
  • 4,534
  • 4
  • 40
  • 65
3

Here is another option. Slightly modified from this blog post

app.factory('ParentCtrl',function(){
    $scope.parentVar = 'I am from the parent'
  };
});

app.controller('ChildCtrl', function($scope, $injector, ParentCtrl) {
  $injector.invoke(ParentCtrl, this, {$scope: $scope});
});

here is a plunker

AgDude
  • 1,167
  • 1
  • 10
  • 27