3

As of recently I have been declaring functions and properties for my angularJS controllers in the following way (app is set to the main apps angular module):

app.controller('myController', ['$scope', function($scope) {
    $scope.myProperty = "hello world";
    $scope.myFunc = function() {
        // do stuff
    };
}]);

After a while the controllers' $scope grew to contain many utility functions and properties that are not being used directly in my views and would not be applicable to other controllers, so I changed it to this:

app.controller('myController', ['$scope', function($scope) {
    var myProperty = 0, addOne;

    addOne = function(i) {
        return i++;
    };

    $scope.myFunc = function() {
        myProperty = addOne(myProperty);
        // do other stuff
    };
}]);

This is working fine but is it okay to declare functions and properties the way shown above or should I extract them out into a service? Can I unit test var declared functions in my controller from jasmine/karma(tried but did not succeed)? What is the best pattern to follow?

I have looked into using the 'this' keyword to accomplish the same thing shown above but I don't think the added value would outweigh the amount of time it would take to convert everything to this pattern. If this is totally wrong please advise a better strategy.

--- Update ---

To answer my own question about testing var declared functions in the controller: How can we test non-scope angular controller methods?

Community
  • 1
  • 1

2 Answers2

3

As a general rule, if you're not going to use the variable or function in the view, don't attach it to the scope. So declare your variables and functions within the controller or on the scope based on it's use. You don't want to put unnecessary stuff on the $scope, as this will slow down the digest cycle. As a best practise I follow this format in my controller:

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

  // controller variables
  var age = 123;

  // scope variables
  $scope.name = 'John';

  // controller functions
  var helloWorld = function() {
    console.log('do work');
  }

  // scope functions
  $scope.isOld = function() {
    return age > 50;
  }

});
user12121234
  • 2,519
  • 2
  • 25
  • 27
  • How would you unit test the "helloWorld" function you have? I have tried but not sure how to make them visible to my jasmine/karma test frameworks. –  Nov 19 '14 at 17:41
  • 1
    I guess if you wanted to run unit tests you'd need to keep your utility functions in a service, which could then be injected into your unit tests for testing. Controller variables and functions would not be available, read up on the scope chain in JavaScript. – user12121234 Nov 19 '14 at 18:05
0

services are singletons while controllers are not. in addition, services are used to share functionality between many different controllers/directives. your second code block looks really good to me for internal, controller specific functionality which you don't need to share in other places in your app, and its much better than putting unneeded stuff in the scope.

sagie
  • 1,744
  • 14
  • 15
  • That's what I was leaning towards but still unsure how I could then test my internally declared functions since they aren't attached to scope. –  Nov 19 '14 at 17:30
  • agree its harder, but in general better not to cloud the scope with irrelevant stuff just for testing. from my experience, testing automation on the client side is very hard to maintain (server side always easy, but UI is always a nightmare) – sagie Nov 19 '14 at 17:34