$watch не обновляется при обновлении объекта службы

Я обнаружил странное обстоятельство, при котором $scope.watch не срабатывает, как я ожидал. Я надеюсь, что некоторые из вас, любители AngularJS, могут помочь пролить свет на то, почему Angular ведет себя так странно с объектами $scope.watch и Service. Как примечание это было обнаружено, когда я возился с Ionic Framework.

Ниже приведен пример того, что я выполняю, и оно работает как положено (будет использоваться для поддержки информации о состоянии во время сеанса).

TL; DR: Watch не запускается на контроллере, когда я обновляю currentUser новым userObject (currentUser = new userObject();) в моем сервисе. Он срабатывает, если я вместо этого обновляю каждый отдельный атрибут объекта.

currentUser.name = 'Foo'; 
currentUser.email = 'foo@bar.com';

Я ищу руководство о том, почему я могу лучше понять.

Код

Сервис (Работающий)

angular.module('app.services')
.service( 'UserService', function() {
    var userObject = function(){
        return {
            id: null,
            username: null,
            email: null,
            fullName: null,
            modified: null
        }
    };
    var currentUser = new userObject();

    var createUser = function(id, username, email, fullName, modified ){
        var newUserObject = new userObject();
        newUserObject.id = id;
        newUserObject.username = username;
        newUserObject.email = email;
        newUserObject.fullName = fullName;
        newUserObject.modified = (modified) ? modified : new Date();
        return newUserObject;
    };

    var setCurrentUser = function(userObj){
        console.log('First');
        console.dir(currentUser);

        setUserId(userObj.id);
        setUsername(userObj.username);
        setEmail(userObj.email);
        setFullName(userObj.fullName);         
        setModifiedDate(userObj.modified);

        console.log('Second');
        console.dir(currentUser);

        return currentUser;
    };

});

контроллер

angular.module('app.controllers')
.controller('DashboardCtrl', function ($scope, UserService) {
    var dashboard = this;

    dashboard.user = UserService.currentUser;

    $scope.$watch('UserService.currentUser', function(newVal, oldVal) {
        if (newVal !== oldVal ){
            dashboard.user = newVal;
        }
    });

    var createdUser = UserService.createUser(
        1,
        'user1',
        'asdf@asdf.com',
        'Test User',
        new Date()
    );
    UserService.setCurrentUser(createdUser);
});

Посмотреть

<div ng-controller="DashboardCtrl as dashboard">
    <span bind="dashboard.user.fullName">Loading</span>
</div>

Результат

Wahoo! Загрузка заменяется на init на '' (null) и сразу после того, как часы обновляются с помощью 'Test User' (быстрее, чем человеческий глаз, если не происходит отладка)

Сценарий взлома

Код выше прекрасно работает. Однако я хотел попытаться уменьшить код, уменьшив повторение усилий, создав новый UserObject, а затем установив этот объект как "Текущий пользователь". Внесенные мною изменения были следующими (вид и контроллер не изменились):

Сервис (Сломанный)

angular.module('app.services')
.service( 'UserService', function() {
    var userObject = function(){
        return {
            id: null,
            username: null,
            email: null,
            fullName: null,
            modified: null
        }
    };
    var currentUser = new userObject();

    var createUser = function(id, username, email, fullName, modified ){
        var newUserObject = new userObject();
        newUserObject.id = id;
        newUserObject.username = username;
        newUserObject.email = email;
        newUserObject.fullName = fullName;
        newUserObject.modified = (modified) ? modified : new Date();
        return newUserObject;
    };

    var setCurrentUser = function(userObj){
        console.log('First');
        console.dir(currentUser);

        // Set original 'currentUser' with a new UserObject passed by controller
        currentUser = userObj;            

        console.log('Second');
        console.dir(currentUser);

        return currentUser;
    };

});

Результат

Загрузка заменяется на '' в init (null), и $scope.watch никогда не срабатывает в этом сценарии. Я ожидаю, что часы должны внимательно следить за объектом, и когда я заменяю объект новым, он должен инициировать изменение объекта и запускать часы.

Единственное, что я могу понять, это то, что когда я заменяю объект currentUser новым объектом, это то, что делегаты для $ watch также теряются на этом объекте. Кто-нибудь знает, как я могу сказать?

Уф.

1 ответ

Когда вы даете строку $watch он проверяет эту переменную внутри угловой функции, так как у вас нет UserService.currentUser в вашей области видимости эта функция наблюдателя никогда не будет запущена.

Чтобы ваши часы работали, вам нужно использовать функцию вместо string, тогда эта функция вернет выражение. Добавив его в функцию наблюдателя, он будет оцениваться в каждом цикле дайджеста и будет выполнять грязную проверку. Если значение меняется, оно запускает функцию наблюдателя

Код

$scope.$watch(function(){
   return UserService.currentUser;
}, function(newVal, oldVal) {
    if (newVal !== oldVal ){
        dashboard.user = newVal;
    }
});
Другие вопросы по тегам