我有一个使用AngularJS和NodeJS后端的简单网站。
它有多个页面,如主页,登录/注册页面等。
我想实施一个"聊天"您可以使用socket.io将消息发送到其他客户端的页面。我已经使用本地控制器(通过本地,我的意思是在单个页面上活动 - 聊天页面)使该部分正常工作。
问题是,我希望聊天系统是全局的(即客户端可以在主页上接收消息,但它们仍然只会在返回聊天页面时显示)。
我在设置聊天控制器全局时遇到问题(在所有页面上都有效)。
以下是我如何包含它:
<body ng-controller="AppCtrl"> <!-- include main controller -->
<div ng-include="'header.tpl.html'"></div>
<div ng-controller="ChatCtrl" class="page"> <!-- include global Chat controller -->
<div ng-view class="container"></div>
</div>
<div ng-include="'footer.tpl.html'"></div>
<!-- ...etc. -->
</body>
这很好用,但似乎我无法从聊天页面访问值。从Chat控制器声明的函数仍然可以被调用,但是&#34; $ scope.message&#34;值(包含被输入的消息)始终为空。
这是我的聊天控制器(实际上称为TravelCtrl)
angular.module('base').controller('TravelCtrl', //['$scope', 'security',
function($rootScope, $scope, security, NgMap, $geolocation, socket){
$scope.messages = [];
// Socket listeners
// ================
socket.on('init', function (data) {
$scope.name = data.name;
$scope.users = data.users;
});
socket.on('send:message', function (message) {
$scope.messages.push(message);
});
socket.on('change:name', function (data) {
changeName(data.oldName, data.newName);
});
socket.on('user:join', function (data) {
$scope.messages.push({
user: 'Server',
text: 'User ' + data.name + ' has joined.'
});
$scope.users.push(data.name);
});
// add a message to the conversation when a user disconnects or leaves the room
socket.on('user:left', function (data) {
$scope.messages.push({
user: 'chatroom',
text: 'User ' + data.name + ' has left.'
});
var i, user;
for (i = 0; i < $scope.users.length; i++) {
user = $scope.users[i];
if (user === data.name) {
$scope.users.splice(i, 1);
break;
}
}
});
// Private helpers
// ===============
var changeName = function (oldName, newName) {
// rename user in list of users
var i;
for (i = 0; i < $scope.users.length; i++) {
if ($scope.users[i] === oldName) {
$scope.users[i] = newName;
}
}
$scope.messages.push({
user: 'Server',
text: 'User ' + oldName + ' has been authenticated as ' + newName + '.'
});
}
// Methods published to the scope
// ==============================
$scope.changeName = function () {
socket.emit('change:name', {
name: $scope.newName
}, function (result) {
if (!result) {
alert('There was an error changing your name');
} else {
changeName($scope.name, $scope.newName);
$scope.name = $scope.newName;
$scope.newName = '';
}
});
};
$scope.sendMessage = function () {
socket.emit('send:message', {
message: $scope.message
});
// add the message to our model locally
$scope.messages.push({
user: $scope.name,
text: $scope.message
});
// clear message box
$scope.message = '';
};
// ================
var init = function () {
$scope.newName = security.currentUser.username;
$scope.changeName();
}
if ($rootScope.hasLoaded() && $scope.name != security.currentUser.username) {
init();
} else {
$rootScope.$on('info-loaded', init);
}
}
//]
);
以及聊天页面本身。奇怪的是,连接的用户和消息显示正确,但控制器似乎无法检索键入的消息。
<div class='col'>
<h3>Users</h3>
<div class='overflowable'>
<p ng-repeat='user in users'>{{user}}</p>
</div>
</div>
<div class='col'>
<h3>Messages</h3>
<div class='overflowable'>
<p ng-repeat='message in messages' ng-class='{alert: message.user == "chatroom"}'>{{message.user}}: {{message.text}}</p>
</div>
</div>
<div class='clr'>
<form ng-submit='sendMessage()'>
Message: {{message}}<br/>
<input size='60', ng-model='message'/>
<input type='submit', value='Send as {{name}}'/>
</form>
</div>
按下&#34;发送&#34;按钮,AngularJS成功调用sendMessage函数,但检索&#34;消息&#34; value作为空字符串,导致它发送一个空的socket.io消息。
我对AngularJS很新,所以我的方法可能完全荒谬。我确信我错过了一些明显的东西,但在重新阅读文档之后,我似乎无法找到什么。
这是组织AngularJS应用程序的正确方法吗?
提前感谢您的帮助。
答案 0 :(得分:1)
这不是关于你的问题,但我看到了我怀疑是错的东西。 当你使用另一个带有angularjs的库时,你应该使用它的桥(例如angular-socket-io)。
当您使用angular进行$ http调用时,它会在回调中正确更新$ scope,并且视图中会显示更改。
在您的代码中:
socket.on('send:message', function (message) {
$scope.messages.push(message);
});
有一个问题:&#34; socket&#34;不是包含在angularjs中的库,所以当调用回调时,你的&#34; $ scope&#34;修改并未正确注意到angularjs。
你必须使用$ scope。$ apply(function(){code here修改$ scope});
示例:
socket.on('send:message', function (message) {
$scope.$apply(function() {
$scope.messages.push(message);
});
});
编辑:
我希望聊天系统是全球性的(即客户端可以在主页上接收消息,但是在返回聊天页面时它们仍然只会显示)。
将数据存储在全局变量中,或使用$ rootScope,它是您在应用程序中使用的所有$ scope的父作用域。
编辑2:
实际上它应该可以解决你的问题;)
另一件事: 1)对全局变量(或全局变量)使用$ rootScope而不是$ scope。在任何$ scope中,您将访问$ rootScope变量($ scope是$ rooScope或父$ scope的副本)。 2)只注册一次socket.io。目前,如果您更改页面,您将在每次更改页面时注册新的回调。
答案 1 :(得分:1)
最近构建了一个大规模的Angular / Socket.IO应用程序,我强烈建议您将所有Socket实现放入一个服务中。此服务将维护您的所有套接字状态,并允许您将其注入任何所需的控制器。这将允许您拥有聊天的主页面,但仍然可以在您的应用程序的其他区域显示通知,聊天用户信息等。