如果我使所有数据对所有控制器可用,我会遇到什么问题?
What problems would I run into if I make all Data available to all Controllers?
我的AngularJS CRUD应用程序通过WebSocket服务器处理它的信息。(这主要是为了让一个用户的更新自动推送给所有用户,而不需要大规模的HTTP轮询)
我很早就意识到,我必须以不同于通常使用HTTP服务的方式设置我的服务。通常,对于我正在使用的每个模型,我为它们提供自己的服务来填充该特定模型。然而,这对于Websocket Connection是不可行的,因为我不希望每个服务都有单独的连接。因此,有几个解决方案。
1)建立一个单独的服务,建立一个连接,然后与其他服务共享该连接,这些服务将使用该服务进行特定的查询
2)创建一个类型无关的服务,供所有需要访问连接和数据的控制器使用。
选项2似乎更容易管理,并且可以跨应用程序重用,所以我开始使用它。那时我才意识到这其实是个机会。我可以创建一个主data
对象,并在数据从请求流入时根据需要动态地创建myService.data
的子对象,而不是为客户端可以接收的每种类型的数据显式地创建模型。因此,如果我需要更新我的模型,我只需在服务器级更新模型,客户端已经知道如何接收它;它只需要一个知道如何使用它的控制器。
然而,这个机会也带来了一个缺点。显然,因为myService.Data
在创建时是一个空的、无子对象,任何想要引用其未来的子对象的Scope都必须简单地引用对象本身。
例如,$scope.user = myService.data.user
抛出一个错误,因为该对象在声明时不存在。看来,我唯一的选择是为每个控制器简单地有$scope.data = myservice.data
,每个控制器的视图将简单地使用< ng-model='data'>
,声明类似于{{data.user.username}}
。我已经测试过了,确实有效。
这是我的服务:
app.factory('WebSocketService', ['$rootScope', function ($rootScope) {
var factory = {
socket: null,
data: {},
startConnection: function () {
//initialize Websocket
socket = new WebSocket('ws://localhost:2012/')
socket.onopen = function () {
//todo: Does anything need to happen OnOpen?
}
socket.onclose = function () {
//todo: Does anything need to happen OnClose?
}
socket.onmessage = function (event) {
var packet = JSON.parse(event.data);
////Model of Packet:
////packet.Data: A serialised Object that contains the needed data
////packet.Operation: What to do with the Data
////packet.Model: which child object of Factory.data to use
////packet.Property: used by Update and Delete to find a specific object with a property who's name matches this string, and who's value matches Packet.data
//Deserialize Data
packet.Data = JSON.parse(packet.Data);
//"Refresh" is used to completely reload the array
// of objects being stored in factory.data[packet.Model]
// Used for GetAll commands and manual user refreshes
if (packet.Operation == "Refresh") {
factory.data[packet.Model] = packet.Data
}
//Push is used to Add an object to an existing array of objects.
//The server will send this after somebody sends a successful POST command to the WebSocket Server
if (packet.Operation == "Push") {
factory.data[packet.Model].push(packet.Data)
}
if (packet.Operation == "Splice") {
for (var i = 0; i < factory.data[packet.Model].length; i++) {
for (var j = 0; j < packet.Data.length; j++){
if (factory.data[packet.Model][i][packet.Property] == packet.Data[j][packet.Property]) {
factory.data[packet.Model].splice(i, 1);
i--;
}
}
}
}
// Used to update existing objects within the Array. Packet.Data will be an array, although in most cases it will usually only have one value.
if (packet.Operation == "Update") {
for (var i = 0; i < factory.data[packet.Model].length; i++) {
for (var j = 0; j < packet.Data.length; j++) {
if (factory.data[packet.Model][i][packet.Property] == packet.Data[j][packet.Property]) {
factory.data[packet.Model][i] = packet.Data[j]
i--;
}
}
}
}
//Sent by WebSocket Server after it has properly authenticated the user, sending the user information that it has found.
if (packet.Operation == "Authentication") {
if (packet.Data == null) {
//todo: Authentication Failed. Alert User Somehow
}
else {
factory.data.user = packet.Data;
factory.data.isAuthenticated = true;
}
}
$rootScope.$digest();
}
},
stopConnection: function () {
if (socket) {
socket.close();
}
},
//sends a serialised command to the Websocket Server according to it's API.
//The DataObject must be serialised as a string before it can be placed into Packet object,which will also be serialised.
//This is because the Backend Framework is C#, which must see what Controller and Operation to use before it knows how to properly Deserialise the DataObject.
sendPacket: function (Controller, Operation, DataObject) {
if (typeof Controller == "string" && typeof Operation == "string") {
var Data = JSON.stringify(DataObject);
var Packet = { Controller: Controller, Operation: Operation, Data: Data };
var PacketString = JSON.stringify(Packet);
socket.send(PacketString);
}
}
}
return factory
}]);
这是一个访问用户信息的简单控制器。它实际上是在Index.html中的永久标头<div>
中使用的,在动态<ng-view>
之外。它负责启动Websocket连接。
App.controller("AuthenticationController", function ($scope, WebSocketService) {
init();
function init() {
WebSocketService.startConnection();
}
//this is the ONLY way that I have found to access the Service Data.
//$scope.user = WebSocketService.data.user doesn't work
//$scope.user = $scope.data.user doesn't even work
$scope.data = WebSocketService.data
});
这里是使用控制器的HTML
<div data-ng-controller="AuthenticationController">
<span data-ng-model="data">{{data.user.userName}}</span>
</div>
您可以做的一件事是将data
对象存储在根作用域上,并在各种控制器上设置监视,以监视它们需要的任何特定于控制器的键:
// The modules `run` function is called once the
// injector is finished loading all its modules.
App.run(function($rootScope, WebSocketService) {
WebSocketService.startConnection();
$rootScope.socketData = WebSocketService.data;
});
// Set up a $watch in your controller
App.controller("AuthenticationController", function($scope) {
$scope.$watch('socketData.user', function(newUser, oldUser) {
// Assign the user when it becomes available.
$scope.user = newUser;
});
});
- 这是什么 ==- javascript 运算符
- 将PHP变量传递给jQuery时遇到问题
- 我的单元测试选项是什么
- 全局变量和全局对象的属性之间有什么区别吗
- 打破承诺链的好方法是什么
- 我的jQuery插件参数没有正确启动,遇到了问题
- 在AngularJS应用程序中使用封装指令和路由的推荐方式是什么
- Javascript中的空白是什么
- 是什么让一个“;Uncaught RangeError:超过了最大调用堆栈大小“;错误(Chrome,在其他浏览器中显示
- 在ember/handlers中使用value和valueBinding有什么区别
- 什么'在webpack外部设置中,reactDom和reactDom不同
- 在JavaScript中拆分日期字符串的更好方法是什么
- 为什么$.brower被弃用?还有什么更好的替代方案
- 什么是&&在没有if的行中的变量之间
- 将jQuery.ech()方法转换为本地JavaScript抽象的最佳方法是什么
- 在将 java 添加到 HTML 时遇到问题,我错过了什么
- 我在 javascript 控制台中编写一个简单的 for 循环时遇到了什么语法错误
- 试图了解脚本应该如何添加以及按什么顺序添加——遇到了困难
- 如果我使所有数据对所有控制器可用,我会遇到什么问题?
- 使用ActiveX时可能遇到的问题/困难是什么?