角度保持对象通过应用程序同步

时间:2014-11-18 18:28:03

标签: javascript angularjs reference

这是一个角度问题以及一个javascript问题。

我的角应用程序中有很多对象来自后端,需要保持最新状态。我无法通过我的应用程序设置好的数据绑定来同步它。

我创建了一个DataService服务,它通过websocket连接到我们的后端。根据需要获取数据并将其本地缓存在名为store的对象中。例如:

当控制器需要用户列表时,它将查询DataService,如下所示:

DataService.get(users, {}).then(
  /* function to set something on the scope */
)
// (or as a resolve)

DataService将从我们的后端获取用户,a)在本地缓存商店对象中的用户,b)返回包含结果的数组。

当另一个控制器需要相同的数据时,我们只返回缓存。


这很有效,除非数据发生变化且后端告诉DataService有关它。 DataService可以更新其本地存储缓存,但控制器不知道这些更改。示例厄运场景:

  • 当控制器需要完整的用户列表时,一段时间后会添加一个新用户(在角度环境之外;通过后端),DataService如何更新之前返回的数组?
  • 控制器可以请求特定的用户子集(例如,来自城市A的所有用户)。当来自城市A的新用户进入系统时,DataService应该如何知道这是控制器感兴趣的东西?如果DataService存储所有查询,则需要一种方法将新用户(例如)与这些查询进行匹配。

2 个答案:

答案 0 :(得分:1)

我是Angular核心中$resource服务的忠实粉丝。使用此选项时,从数据返回的属性将分配给$ resource对象实例上的对象。所以

// js
scope.myThing = $resource('thing_url').get();

// html
{{ myThing.myProperty }}

这可以通过利用Angular的摘要周期来实现。返回资源时,模板“神奇地”起作用。这实际上是因为$resource服务在完成请求时启动了摘要周期,绑定现在显示正确的信息。你可以和观察者做同样的事情:

scope.$watch('myThing.myProperty', function (newValue) { /... });

您可以执行类似的操作:创建一个服务,该服务返回包含服务器结果的对象。假设您可以连接到Web套接字层上的事件,则可以在数据更新时启动摘要周期。这样,控制器和模板将会更新。


问题作者补充:

在服务中踢消化周期只是工作的一半。另一半是确保不覆盖对象(单个模型)和数组(模型集合)的引用。您可以实现此by using angular.copy when updating the local models inside your service

我们工作解决方案的伪代码:

  • 在API服务中创建商店对象(用作所有数据库数据的缓存)
  • 每当控制器需要某些信息时,它都会查询API服务。
  • API服务从后端请求数据并将其本地存储在商店对象中。
  • 除了商店对象,我们还创建了一个最小的查询解析器,能够以与后端过滤器相同的方式过滤商店对象(我们有一个mongo样式查询API,其中查询是{city: "amsterdam"}或{{1}之类的对象})。
  • 对本地存储运行查询,保存查询和结果,并将其传回给请求者(指令或控制器)。
  • 每当模型更新时,请重新运行可能关联的所有查询。如果结果发生变化,请使用{city: {"!": "amsterdam"}}更改对象/数组而不丢失引用。之后启动摘要周期,以便控制器知道数据的变化。

这解决了所有的doomscenarios:

  

当控制器需要完整的用户列表时,在一段时间后添加新用户(在角度环境之外;通过后端),DataService如何更新先前返回的数组?

copy.angular

  

控制器可以请求特定的用户子集(例如,来自城市A的所有用户)。当来自城市A的新用户进入系统时,DataService应该如何知道这是控制器感兴趣的东西?如果DataService存储所有查询,则需要一种方法将新用户(例如)与这些查询进行匹配。

每当基础数据发生变化时,服务都会自动重新运行所有查询。这样,该服务将使整个角度范围内的所有数据保持最新。

答案 1 :(得分:0)

有两种方法可以做到这一点。两者都要求您将$rootScope注入您的服务。

如果你在控制器中使用$scope.users = DataService.users这样的东西,第一种方法是好的。只需触发所有范围即可更新传入的消息,例如:

$rootScope.$apply(function () {
    users.push(newUser);
});

第二种方法是在收到来自服务器的消息时从根作用域广播事件:

$rootScope.$broadcast('server:update', data);

在你的控制器中听它:

$scope.$on('server:update', function (data) {
    // Whatever you need to do
});