Javascript 角度JS绑定等待输入

Javascript 角度JS绑定等待输入,javascript,angularjs,node.js,sockets,Javascript,Angularjs,Node.js,Sockets,我正在使用Angular JS和Socket.io开发一个简单的聊天室。我让客户端在不插入套接字的情况下工作得很好。然而,在我添加了套接字通信之后,绑定就搞砸了 我输入信息并点击send。addMessage被激发,然后“chat message”套接字事件被激发。但是,在我键入另一封信或再次单击“发送”之前,用户界面不会得到更新。然后绑定发挥其魔力,UI添加消息 有什么想法吗 js文件 //Receive Socket message. //Runs but UI does not updat

我正在使用Angular JS和Socket.io开发一个简单的聊天室。我让客户端在不插入套接字的情况下工作得很好。然而,在我添加了套接字通信之后,绑定就搞砸了

我输入信息并点击send。addMessage被激发,然后“chat message”套接字事件被激发。但是,在我键入另一封信或再次单击“发送”之前,用户界面不会得到更新。然后绑定发挥其魔力,UI添加消息

有什么想法吗

js文件

//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>

{{message.text}


我可能会错过一些上下文,但这一切看起来都像是在角度摘要周期之外更新
$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
你需要的范围(但这是最不干净的解决方案)。

你能试着在
$scope.clear()之后添加
$scope.$apply()
?我从未使用过
ng表单
,如果它没有为您消化范围,我会感到惊讶,但可能我们缺少了一些内容。@floribon$scope.$apply()有效!非常感谢。如果你加上它作为回答,我将欣然接受。如果您也能解释一下,我将不胜感激。@RyanTankersley,Angular不“知道”异步操作何时完成,不知道何时应用更改(即开始$digest循环)<代码>$scope.$apply
手动触发。好的,我在紧接着的更新中回答并添加了更多信息。不确定你的
socket
对象是什么样子的,但是你可能想围绕它做一些工作,这样它就可以一次性修复。