AngularJS: Hitting a strange issue with $scope variables

In the following code, whenever you delete an item from the delete link in the list, it will only delete the item from the list, but it will not delete the currently selected item. (The item displaying once you click on it). However, if you click on the delete link next to the currently selected item, it will delete from both places.

To replicate what I'm seeing:

  • Add a bunch of items by typing in the text box and hitting enter a few times.
  • Select one of the items from the list.
  • Click delete next to the item when it displays below.
  • This is the correct behavior.
  • Select another item you created earlier.
  • Now click the delete link next to the item in the list.
  • The item is removed from the list, but not the currently displayed item.

When I step into the code $scope.currentUser is undefined when I click on the delete link in the list.

Why is this happening?

<html ng-app="myApp">
<head>
    <script src="http://code.angularjs.org/1.0.1/angular-1.0.1.min.js"></script>
    <script>
    var app = angular.module('myApp', []);

    app.config(function($routeProvider) {
        $routeProvider.when('/User/:id', {
            controller: UserCtrl,
            template: '<h1>{{currentUser.name}}</h1> <a ng-click="deleteUser(currentUser.id)">delete me</a>'
        });
    });

    app.factory('userSvc', function(){ 
        return new UserService();
    });

    function UserCtrl($scope, $routeParams, $location, userSvc) {
        var currUser = userSvc.getUser($routeParams.id);
        $scope.currentUser = currUser;
        $scope.users = userSvc.getAllUsers();

        $scope.addUser = function () {
            var user = { 
                id: userSvc.nextId(),
                name: $scope.addUserName
            };
            userSvc.addUser(user);
            $scope.addUserName = '';
            $location.url('/User/' + user.id);
        };

        $scope.deleteUser = function(id) {      
            if($scope.currentUser != null && $scope.currentUser.id == id) {
                $scope.currentUser = null;
            }
            userSvc.delete(id);
        };
    };

    function UserService() {
        var users = [{id: 1, name: 'Ben' }];

        this.delete = function(id) {
            for(var i = 0; i < users.length; i++) {
                var user = users[i];
                if(user.id == id) {
                    users.splice(i,1);
                }
            }
        };

        this.addUser = function(user) {
            users.push(user);
        };

        this.getAllUsers = function() {
            return users;
        };

        this.getUser = function(id) {
            for(var i = 0; i < users.length; i++) {
                var user = users[i];
                if(user.id == id) {
                    return user;
                }
            }
        };

        this.nextId = function() {
            var maxId = 0;
            for(var i = 0; i < users.length; i++) {
                var user = users[i];
                maxId = Math.max(maxId, user.id);
            };
            return maxId + 1;
        };
    }
    </script>
</head>
<body>
<div ng-controller="UserCtrl">
    <form ng-submit="addUser()">
        <input ng-model="addUserName" type="text"/>
        <input type="submit" value="Add"/>
    </form>
    <ul>
        <li ng-repeat="user in users"><a href="#/User/{{user.id}}">{{user.name}}</a> <a ng-click="deleteUser(user.id)">delete</a></li>
    </ul>
</div>
<div ng-view></div>
</body>
</html>

It turns out that selecting a user from the list actually also created a brand new scope that was seperate from the one used to bind the list.

Thanks to Gloopy's comment above to check out Batarang, I was able to see this happen. If this happens to help you, please +1 his comment.

According to the documentation on Scopes some directives will actually cause a new scope to be created. I'm assuming that clicking a link that is being handled by the $routeProvider also results in the creation of a whole new scope tree, likely because it's creating another instance of that controllor.