模型更改后,AngularJS视图未更新

时间:2016-11-11 19:11:06

标签: javascript angularjs node.js express

我正在编写一个基于网络的游戏,允许您对卡片进行投标并与其他玩家进行交易。对于这个应用程序,我使用Node,Express,MongoDB和Angular。

该视图显示了玩家头像和名称及其连接状态。此连接状态保存在游戏模型中,但也通过socket.io websockets实时跟踪。

当玩家加入游戏时,服务器会向所有客户端发送消息。然后,客户通过比较游戏ID来检查消息是否适合他们。

socketService.on("playerConnection", function(data) {
    if (data.gameId === gameId) {
        handlePlayerConnection(data);
    }
});

如果邮件是针对我们的客户端的,则数据会传递给函数'handlePlayerConnection'。

function handlePlayerConnection(data) {
    if ($scope.game) {
        for (var i = 0; i < $scope.game.players.length; i++) {
            if ($scope.game.players[i].user.id === data.userId) {
                $scope.game.players[i].isConnected = data.connected;
            }
        }
    }
}

在视图中,我只是将玩家头像绑定到'isConnected',因此当玩家连接/断开连接时显示/隐藏。

游戏模型经常发生变化(显然),服务器告诉客户端(再次通过套接字)刷新$ scope.game。

下面的代码显示了$ scope.game的刷新方式。

function getGame(gameId, callback) {
    gameService.getGame(gameId, function(err, data) {
        if (!err) {
            $scope.game = data; // Set game

            if (callback) callback(data);
        }
    });
}

此时,视图基本上已冻结。它完全停止响应播放器连接和断开连接。刷新浏览器或控制器可以解决问题。

我已将$ scope.game.players记录到控制台,它似乎包含正确的连接状态。该视图根本没有响应。 我试图以各种方式和地点实现$ scope。$ apply()但是所有这些都给了我' angular.js:13920错误:[$ rootScope:inprog] $申请已经在进行中' 。包装$ scope。$ timeout()中的$ apply()消除了上述错误,但没有解决问题。

花了好几个小时试图解决这个问题之后,我可能会遇到一个隧道视觉案例。对任何可以帮助我的人都有无尽的荣誉。

编辑:刚刚意识到所有套接字数据都是通过$ rootScope.apply()处理的。 完整代码:

var socket = io.connect("http://localhost:8180/");
return {
    on: function(eventName, callback) {
        socket.on(eventName, function() {
            var args = arguments;
            $rootScope.$apply(function() {
                callback.apply(socket, args);
            });
        });
    },
    emit: function(eventName, data, callback) {
        socket.emit(eventName, data, function() {
            var args = arguments;
            $rootScope.$apply(function() {
                if (callback) {
                    callback.apply(socket, args);
                }
            });
        })
    },
    off: function(eventName) {
        socket.off(eventName);
    }
};

现在我甚至不太确定该怎么做..

2 个答案:

答案 0 :(得分:0)

if (!$scope.$$phase) {
    $scope.game = data; // Set game

    if (callback) callback(data);
}

如果当前没有进行摘要,这将触发摘要。否则,您的代码将通过正在运行的摘要进行更新。

答案 1 :(得分:0)

最后解决了......

我忘记了我正在使用指令作为'玩家'。由于懒惰的原因,我没有创建一个独立的范围并传递播放器对象,而是通过以下方式将播放器对象分配给范围:

link: function(scope, elem, attrs) {
        /*
            Decided not to use an isolated scope because the
            player directive needs access to the $rootScope.
            The solution below eliminates the need of said scope.
        */
        scope.player = scope.$eval(attrs.player);

    }

如你所见,甚至还有一条评论解释了我的愚蠢决定。