Angular JS绑定等待直到输入

时间:2015-05-05 22:51:22

标签: javascript angularjs node.js sockets

我正在使用Angular JS和Socket.io来尝试开发一个简单的聊天室。当没有插入插座时,我让客户端工作得很好。然而,在我添加套接字通信之后,绑定就搞乱了。

我输入消息并点击发送。触发addMessage,然后触发'chat message'套接字事件。但是,在我键入另一个字母或再次单击“发送”之前,UI不会更新。然后绑定发挥其魔力,UI添加消息。

有什么想法吗?

js file

//Receive Socket message.
//Runs but UI does not update.
//UI updates on user's next input
$scope.socket.on('chat message', function(msg) {
    var message = new Message(msg);
    $scope.messages.splice(0, 0, message);
    $scope.clear();
});

//Add Message, sends to socket
$scope.addMessage = function () {
  if($scope.validate()) {
    var message = new Message($scope.message);
    $scope.socket.emit('chat message', message.text);
  }
};

html文件

<form role="form" ng-submit="addMessage()">
    <div class="row">
        <div class="input-group" style="margin-bottom: 5px;">
            <input type="text" ng-model="message" placeholder="What's up?" class="form-control" ng-change="validate()">
                <span class="input-group-btn">
                    <input type="submit" class="btn btn-primary" value="Add"/>
                </span>
            </input>
        </div>
    </div>
</form>
<div ui-sortable ng-model="messages">
    <div ng-repeat="message in messages"  style="padding:5px 10px;">
        <p>{{ message.text }}</p>
    </p>
</div>

1 个答案:

答案 0 :(得分:0)

我可能会错过一些上下文,但看起来你好像正在更新Angular摘要周期之外的$scope,通常是来自服务器调用的异步代码块或setTimeout

Angular不知道范围已在此类同步上下文中更新,并且在下一个摘要周期之前不会刷新DOM(例如,在您的情况下通过某些键盘输入触发)。

为了强制Angular手动摘要,您需要在更新后调用$scope.apply

$scope.socket.on('chat message', function(msg) {
  var message = new Message(msg);
  $scope.messages.splice(0, 0, message);
  $scope.clear();
  $scope.apply();
});

或者在回调中进行更新,如下所示:

$scope.socket.on('chat message', function(msg) {
  $scope.$apply(function() {
    var message = new Message(msg);
    $scope.messages.splice(0, 0, message);
    $scope.clear();
  });
});

(优点是Angular将处理并委托抛出的任何错误。)

更新:好的,我只是意识到您正在使用自定义$scope.socket事件发射器,我认为这是第一次阅读时的常规$scope.$emit。因此,干净的方法是直接在socket.emit函数中应用范围。如果这是一项服务,您可以在此服务中注入$rootScope并将发射封装在$rootScope.apply(...)内。或者使用$timeout。或者如果它是一个完全没有棱角分明的东西,可以不用它来搞乱角度物品并将它包装成角度服务,或者只需$apply你的范围(但那是最不干净的解决方案)。