$ watch更新服务对象时不会更新

时间:2015-08-17 20:14:32

标签: angularjs angularjs-service angularjs-controller angularjs-watch

我发现了一个令人困惑的情况,其中$ scope.watch没有像我期望的那样触发。我希望你们中的一些AngularJS buff可以帮助解释为什么Angular在$ scope.watch和Service对象中表现得如此特殊。作为一个注释,这是在我弄乱Ionic框架时发现的。

以下是我正在运行的示例,它按预期工作(用于在会话期间维护状态信息。)

TL; DR: 当我在我的服务中使用新的userObject(currentUser = new userObject();)更新currentUser时,Watch不会在控制器上触发。如果我改为更新对象的每个单独属性,它就会触发。

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>

结果

嗬!加载在init上替换为&#39;&#39;&#39; (null)并在手表更新后立即使用“测试用户”#39; (除非调试,否则比人眼更快)

打破场景

上面的代码效果很好。但是,我想通过创建一个新的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;
    };

});

结果

正在使用&#39;&#39;替换在init(null)和$ scope.watch从不在这种情况下触发。我的期望是手表应该对物体进行深入观察,当我用新物体替换物体时,它应该触发物体改变并触发手表。

我唯一可以想到的是,当我用new对象替换currentUser对象时,$ watch的委托也会丢失在该对象上。有谁知道我怎么说?

呼。

1 个答案:

答案 0 :(得分:2)

当你给$watch一个字符串时,它会检查角度函数中的变量,因为你的范围内没有UserService.currentUser,那么观察者函数永远不会被触发。

为了让你的手表正常工作,你需要使用函数而不是string,然后该函数将返回一个表达式。通过将其添加到观察器功能中,以便在每个摘要周期中对其进行评估。将执行脏检查。如果值得到改变,它将触发观察者功能

<强>代码

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