Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AngularJS - Why does $scope.$apply affect other scopes

Tags:

angularjs

In my AngularJS app, I have 2 controllers which are not nested. Calling the $scope.$apply method seems to affect the other sibling scope as well.

In the jsfiddle below, it seems that the ControllerOne's {{doubleMe(x)}} expression is evaluated whenever ControllerTwo updates the clock every second. This can be shown from the console message.

I can understand why that expression is evaluated whenever the text input (on the same scope) changes, but why would $scope.$apply on another scope cause that expression to be re-evaluated as well?

Note that I could have avoided $scope.$apply by using $timeout, but the outcome is observed.

    <!-- HTML file -->
    <div ng-app>
        <h1>Root</h1>
        <div ng-controller="ControllerOne">
            <h2>Scope One</h2>
            1 * 2 =  {{doubleMe(1)}}<br/>
            2 * 2 =  {{doubleMe(2)}}<br/>
            3 * 2 =  {{doubleMe(3)}}<br/>
            <input ng-model="text">
        </div>

        <div ng-controller="ControllerTwo">
            <h2>Scope Two</h2>
            {{clock.now | date:'yyyy-MM-dd HH:mm:ss'}}
        </div>
    </div>

// js file

    function ControllerOne($scope) {
        var counter=1;
        $scope.doubleMe = function(input) {
            console.log(counter++);
            return input*2;
        }
        $scope.text = "Change Me";
    }

    function ControllerTwo($scope) {
        $scope.clock = {
            now: new Date()
        };

        var updateClock = function() {
            $scope.clock.now = new Date()
        };

        setInterval(function() {
            $scope.$apply(updateClock);
        }, 1000);
    }
like image 330
Kelvin Yong Avatar asked Aug 25 '26 22:08

Kelvin Yong


1 Answers

as you can see $scope.$apply = $rootScope.$digest //+ some error handling and since $scope.$apply uses $rootScope it affects all its descendants.

so If you update a child scope, you can call $scope.$digest to dirty-check only that scope and its descendants and as a result you reduce the number of dirty-checks and increase your performance.

Example

I changed your code and added $digest.

setInterval(function() {
             $scope.clock.now = new Date();
            $scope.$digest();
        }, 1000);

Live example: http://jsfiddle.net/choroshin/JY5sb/4/

like image 174
Alex Choroshin Avatar answered Sep 02 '26 23:09

Alex Choroshin