$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;
}
});