4

I have a simple hashmap and a simple method which displays the status in text, but when I update only 1 user-status, all of them are getting updated (function is called for all users). Is there a way to update only one element and not all of them?

Example code is here, just see what happens in console when you click on the "Change Status" button.

HTML:

<div ng-app="myApp">
  <div ng-controller="Ctrl">
    <div class="user-panel" ng-repeat = "(id, user) in _users">
        Status: 
        <span class="user-status{{user.status}}">
            {{getStatusInText(user.status)}}
        </span>
        <hr>
        <div class="toLeft">(<b>{{id}}</b>) {{user.name}}</div>
        <div class="toRight">
            <button ng-click="changeUserStatus(id, '1')">Change Status</button>
        </div>
       <div class="clear"></div>
    </div>
  </div>    
</div>

AngularJS:

var app = angular.module('myApp', []);

function Ctrl($scope) {
    $scope._users = {"123":{"name":"test","status":"0"}, "124":{"name":"test2", "status":"0"},"125":{"name":"test2", "status":"0"}};

    $scope.getStatusInText = function(status) {
        console.log("CALLED: " + status);
        return (status === "1") ? "online" : "offline";
    }

    $scope.changeUserStatus = function(uId, status) {
        $scope._users[uId].status = status;

    }
}

And the fiddle for above example:

http://jsfiddle.net/ztVnj/3

another example with iteration, which is called everytime with the getStatusInText function.

http://jsfiddle.net/ztVnj/4/

Vural
  • 8,666
  • 11
  • 40
  • 57
  • 2
    `changeUserStatus` is only getting called once, but the entire view is being updated, so `getStatusInText` is being called once for each user. – Shmiddty Feb 19 '13 at 23:53
  • What if I have 100 elements in the hashmap and more operations in getStatusInText() function, like iterations etc. ? Would it not slowdown the page ? – Vural Feb 19 '13 at 23:57
  • Only 100 elements will call the function 300 times and with iterations it will be more work for the page. On scrolling Up/Down while calling the method, the page will be frozen. – Vural Feb 20 '13 at 00:03
  • http://www.bennadel.com/blog/2443-Rendering-DOM-Elements-With-ngRepeat-In-AngularJS.htm – Shmiddty Feb 20 '13 at 00:08
  • I think it is by design. Angular have no idea whether your `getStatusInText` stay same for other elements or not. You can always make function otherwise, in such case evaluation has to iterate. – Tosh Feb 20 '13 at 01:42
  • What you want is "track by". More info: http://stackoverflow.com/questions/17079541/angularjs-ng-repeat-with-dynamic-list-without-rebuilding-entire-dom-tree – Jason Axelson Apr 14 '15 at 20:23

1 Answers1

5

Updated example: http://jsfiddle.net/ztVnj/5/

Theory here:

Move the expensive operation outside the hashmap, and manually control the update. As already mentioned, if the hashmap is changed at all, the whole ng-repeat is redrawn.

Changes:

Binding to $scope, add an array to map status values to ids.

$scope._users = {"123":{"name":"test","status":"0"}, "124":{"name":"test2", "status":"0"},"125":{"name":"test2", "status":"0"}};
$scope._userStatus = [];

Change template to look up this array instead:

Status: <span class="user-status{{user.status}}">{{_userStatus[id]}}</span>

Update the changeStatus function to be the only place the status text is updated, and then perform one initial iteration at the beginning.

$scope.changeUserStatus = function(uId, status) {
    console.log("Button Clicked.");
    $scope._userStatus[uId] = $scope.getStatusInText(status);
}

angular.forEach($scope._users, function(user, uId) {
    $scope._userStatus[uId] = $scope.getStatusInText(user.status);
});
Alex Osborn
  • 9,831
  • 3
  • 33
  • 44