在AngularJS中使用范围和控制器时发生冲突

我有一个使用AngularJS和NodeJS后端的简单网站。

它有多个页面,如主页,login/注册页面等

我想实现一个“聊天”页面,您可以使用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> 

这工作相当好,但似乎我不能从我的聊天页面访问值,但。 从聊天控制器声明的函数仍然可以被调用,但是“$ scope.message”值(包含正在键入的消息)始终是空的。


这里是我的聊天控制器(这实际上叫做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); } } //] ); 

以及聊天页面本身。 奇怪的是,连接的用户和消息显示正确,但控制器似乎无法检索input消息。

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

当按下“发送”button时,AngularJS成功地调用了sendMessage函数,但是将“message”值作为空string检索,导致它发送一个空的socket.io消息。


AngularJS对我来说很新,所以我的做法可能是荒谬的。 我相信我错过了一些明显的东西,但在重新阅读文档之后,我似乎无法find答案。

这是组织一个AngularJS应用程序的正确方法吗?

在此先感谢您的帮助。

在最近构build了一个大型的Angular / Socket.IO应用程序之后,我强烈build议你将所有的Socket实现都放到一个Service中。 该服务将保持您的所有套接字状态,并允许您将其注入任何所需的控制器。 这将允许你有一个聊天的主页面,但是仍然能够在你的应用程序的其他区域显示通知,聊天用户信息等。

这不是关于你的问题,但我看到一些我怀疑是错的东西。 当你使用angularjs的另一个库,你应该使用一个桥梁(例如angular-socket-io)。

当您使用angular进行$ http调用时,它会在callback中正确更新$ scope,并且可以在视图中看到更改。

在你的代码中:

 socket.on('send:message', function (message) { $scope.messages.push(message); }); 

有一个问题:“套接字”不是包含在angularjs中的库,所以当调用callback函数时,你的“$ scope”修改没有被正确地注意到angularjs。

你必须使用$ scope。$ apply(function(){code here修改$ scope});

例:

 socket.on('send:message', function (message) { $scope.$apply(function() { $scope.messages.push(message); }); }); 

编辑:

我希望聊天系统是全球性的(即,客户端可以在主页上接收消息,但是在返回聊天页面时仍然只能显示)。

可以将数据存储在全局variables中,也可以使用$ rootScope,它是您在应用程序中使用的所有$ scope的父范围。

编辑2:

其实它应该可以解决你的问题;)

另一件事:1)使用$ rootScope而不是$ scope作为全局variables(或全局variables)。 在任何$作用域中,您将访问$ rootScopevariables($ scope是$ rooScope或$ $ scope的副本)。 2)只注册一次socket.io。 目前,如果您更改页面,您将在每次更改页面时注册新的callback。