Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should I always bind functions to $scope objects?

When I'm creating controllers, I always add functions to the $scope object, like so:

function DummyController($scope) {

  $scope.importantFunction = function () { /*...*/ };

  $scope.lessImportantFunction = function () { /*...*/ };

  $scope.bussinessLogicFunction = function () { /*...*/ };

  $scope.utilityFunction = function () { /*...*/ };

}

Of course I'm keeping my controllers encapsulated nicely, making sure that business logic lies in appropriate components (injected via DI) or services. So the controller is focused on orchestrating things between UI and Backend.

However, as you can see - there are still plenty of different kinds of functions. I like to keep more of them, as it improves readability IMHO.

The question Is that a good practice to have lots of functions attached to $scope object? Does it have performance overhead? I know that $scope is a special kind of object, being constantly evaluated in Angular's digest cycle, so am I doing this right or will I ask for trouble by sticking to my approach?

(Please note: I'm not looking for alternative approaches. I'm looking for some well thought analysis of people who know Angular's internals.)

Thx!

UPDATE:

The answer from Anders is very good and shows you some paths to follow. Today I ran into this beauty, a chrome extension for Angular Js debugging and performance monitoring. It shows you all the scopes and assigned variables, along with some interesting performance graph. A must have for any Angular developer!

like image 879
ŁukaszBachman Avatar asked Feb 22 '13 07:02

ŁukaszBachman


1 Answers

Update:

  1. Should I add all of my functions and variables to the scope?

    No, you should only add functions and variables to your scope if you need to access them in your template. A variable that is only accessed in the controller function shouldn't be on the scope, it should be local to the controller function.

  2. Will if affect performance if I add a lot of functions to the scope?

    Generally, no. Functions on your scope that are executed like ng-click="myFunction()" should not affect performance in a noticeable way. But if your function is executed like this: {{myFunction()}} it will get executed for every digest as Angular needs to know if the return value of it has changed so it can update the UI.

  3. Will it affect performance if I add a lot of variables to the scope?

    It can affect performance if you use them in places where Angular will dirty check them. Those cases are where you print them out like {{myVariable}}, if you use them in ng-model="myVariable", ng-show="myVariable", etc. Directives like ng-click does not perform dirty checks, so that doesn't slow things down. The guys behind Angular recommends you not to use more than 2000 expressions on one page that will require repaints/dirty checks, as your performance will start do degrade after that. The limit of 2000 is something they've found while researching performance in Angular.

    Note that just because you add a property on the scope, it doesn't mean that Angular will perform dirty checks on it. They have to be used in your template for dirty checks to be performed (but not for ng-click).

  4. If I want maximum performance in my Angular app, what should I be aware of?

    Like I mentioned above, try to keep the number of bound template expressions below 2000. And if you implement watches on your scope, make sure that the expression for the watch executes really quickly. This is an example of how you shouldn't do it:

    $scope.items = [];
    for (var i = 0; i < 1000; i++) {
        $scope.items.push({prop1: 'val1', prop2: 'val2', prop3: 'val3'});
    }
    
    $scope.$watch('items', function() {
    
    }, true);
    

    By adding the true as the third argument to $watch, you're telling Angular to loop through $scope.items for every digest cycle to check if any property of the thousand items have changed, which will be costly both in time and memory.

    What you should do instead is:

    $scope.items = [];
    for (var i = 0; i < 1000; i++) {
        $scope.items.push({prop1: 'val1', prop2: 'val2', prop3: 'val3'});
    }
    
    $scope.$watch('items.length', function() {
    
    });
    

    That is, only check when $scope.items.length have changed. That expression will execute very quickly.


Original post:

If your question is "is it better to expose functions to the template than objects" then yes, you should be using functions as much as you can. That way you encapsulate the logic inside the controller instead of letting it bleed into your template. Take this example:

<div ng-show="shouldShow">Toggled div</div>
<button ng-click="shouldShow = !shouldShow">Toggle<button>

Here the template has a little too much knowledge about what's happening. Instead, this should be solved like this:

// controller
var shouldShow = false;
scope.toggle = function() {
    shouldShow = !shouldShow;
}
scope.shouldShow = function() {
    return shouldShow;
}

<!-- template -->
<div ng-show="shouldShow()">Toggled div</div>
<button ng-click="toggle()">Toggle<button>

By doing it like this it's trivial to expand the logic in the controller without touching the template. While your requirements right now might be to just toggle the div when you press the button, tomorrows requirements might be to update some other part of the application when that happens. And if you use a function instead, it's easy to add that logic inside the function without changing the template.

Functions on your scope have a bit more overhead than using properties, but that overhead probably won't be what's slowing down your app when that day comes. So use functions when they make sense.

But you should still try to keep your controllers as small as possible. If they grow to contain tons of functions/functionality, you should probably split up your controller into reusable directives.

like image 65
Anders Ekdahl Avatar answered Oct 23 '22 22:10

Anders Ekdahl