当前位置: 首页 > 知识库问答 >
问题:

AngularJS:如何监视服务变量?

何和惬
2023-03-14

我有一个服务,说:

factory('aService', ['$rootScope', '$resource', function ($rootScope, $resource) {
  var service = {
    foo: []
  };

  return service;
}]);

我想使用foo来控制以HTML呈现的列表:

<div ng-controller="FooCtrl">
  <div ng-repeat="item in foo">{{ item }}</div>
</div>

以便控制器检测何时维修。foo更新了,我拼凑了这个模式,将服务添加到控制器的$范围,然后使用$范围$watch()

function FooCtrl($scope, aService) {                                                                                                                              
  $scope.aService = aService;
  $scope.foo = aService.foo;

  $scope.$watch('aService.foo', function (newVal, oldVal, scope) {
    if(newVal) { 
      scope.foo = newVal;
    }
  });
}

这让人觉得很费时,我一直在每个使用服务变量的控制器中重复这一点。有没有更好的方法来完成监视共享变量的任务?


共有3个答案

乌鸿宝
2023-03-14

我使用与@dtheodot类似的方法,但使用角度promise,而不是传递回调

app.service('myService', function($q) {
    var self = this,
        defer = $q.defer();

    this.foo = 0;

    this.observeFoo = function() {
        return defer.promise;
    }

    this.setFoo = function(foo) {
        self.foo = foo;
        defer.notify(self.foo);
    }
})

然后在任何地方使用myService.setFoo(foo)方法在服务上更新foo。在您的控制器中,您可以将其用作:

myService.observeFoo().then(null, null, function(foo){
    $scope.foo = foo;
})

然后的前两个参数是success和error回调,第三个参数是notify回调。

q美元参考。

易元青
2023-03-14

在这样的场景中,如果多个/未知对象可能对更改感兴趣,请使用$rootScope$从正在更改的项目广播。

与其创建自己的侦听器注册表(必须在各种$销毁时清理),您应该能够从相关服务$广播

您仍然必须在每个侦听器中的处理程序上对$进行编码,但该模式与对$摘要的多个调用分离,从而避免了长时间运行的监视程序的风险。

这样,监听器也可以从DOM和/或不同的子作用域来来去去,而不需要服务更改其行为。

**更新:示例**

广播在“全球”服务中最有意义,这可能会影响应用程序中的无数其他内容。一个很好的例子是用户服务,其中可能发生许多事件,例如登录、注销、更新、空闲等。我认为这是广播最有意义的地方,因为任何作用域都可以侦听事件,甚至不需要注入服务,而且它不需要计算任何表达式或缓存结果来检查更改。它只是触发并忘记(因此,请确保这是一个触发并忘记通知,而不是需要采取行动的事情)

.factory('UserService', [ '$rootScope', function($rootScope) {
   var service = <whatever you do for the object>

   service.save = function(data) {
     .. validate data and update model ..
     // notify listeners and provide the data that changed [optional]
     $rootScope.$broadcast('user:updated',data);
   }

   // alternatively, create a callback function and $broadcast from there if making an ajax call

   return service;
}]);

当save()函数完成且数据有效时,上述服务将向每个作用域广播一条消息。或者,如果是$资源或ajax提交,请将广播调用移动到回调中,以便在服务器响应时触发。广播特别适合这种模式,因为每个侦听器都只是等待事件,而不需要检查每个$摘要上的范围。侦听器看起来像:

.controller('UserCtrl', [ 'UserService', '$scope', function(UserService, $scope) {

  var user = UserService.getUser();

  // if you don't want to expose the actual object in your scope you could expose just the values, or derive a value for your purposes
   $scope.name = user.firstname + ' ' +user.lastname;

   $scope.$on('user:updated', function(event,data) {
     // you could inspect the data to see if what you care about changed, or just update your own scope
     $scope.name = user.firstname + ' ' + user.lastname;
   });

   // different event names let you group your code and logic by what happened
   $scope.$on('user:logout', function(event,data) {
     .. do something differently entirely ..
   });

 }]);

这样做的好处之一是消除了多个手表。如果像上面的示例那样组合字段或派生值,则必须同时查看firstname和lastname属性。只有当用户对象在更新时被替换时,才能监视getUser()函数,如果用户对象只是更新了其属性,则不会触发该函数。在这种情况下,你必须做一个深度观察,这是更密集的。

$广播将消息从它调用的范围向下发送到任何子范围。因此从$rootScope调用它将在每个范围内触发。例如,如果您要从控制器的范围内广播$,它将仅在继承自控制器范围的范围内触发。$emit方向相反,行为类似于DOM事件,因为它在范围链中冒泡。

请记住,有些场景中$broadcast很有意义,有些场景中$watch是一个更好的选择-尤其是在具有非常特定的watch表达式的隔离范围中。

巴帅
2023-03-14

如果您想避免$watch的暴政和开销,您可以始终使用良好的旧观察者模式。

在服务中:

factory('aService', function() {
  var observerCallbacks = [];

  //register an observer
  this.registerObserverCallback = function(callback){
    observerCallbacks.push(callback);
  };

  //call this when you know 'foo' has been changed
  var notifyObservers = function(){
    angular.forEach(observerCallbacks, function(callback){
      callback();
    });
  };

  //example of when you may want to notify observers
  this.foo = someNgResource.query().$then(function(){
    notifyObservers();
  });
});

在控制器中:

function FooCtrl($scope, aService){
  var updateFoo = function(){
    $scope.foo = aService.foo;
  };

  aService.registerObserverCallback(updateFoo);
  //service now in control of updating foo
};
 类似资料:
  • 问题内容: 在angularJs中可以观看全局变量吗? 我从旧版代码中设置了一个window.test变量,然后我需要观察该变量以了解它是否存在。 我尝试过类似的东西 问题答案: 有些。您可以包含Angular 服务(如文档所述,比直接访问更安全): 然后使用watch函数作为您的第一个参数,如下所示: 演示小提琴 但是请注意,只有在触发Angular进行$ digest操作后,才会执行。一种可行

  • 问题内容: 我正在写指令,并且需要注意父作用域的更改。不知道我是否正在按照首选方式执行此操作,但是它不能与以下代码一起使用: 它记录了窗口加载,但是即使更改了overlaytype,也不会再次登录。 我怎样看待变化? 编辑:这是整个指令。不确定我为什么要使用儿童镜 问题答案: 您应该在子作用域上具有 data 属性,作用域在父作用域和子作用域之间使用原型继承。 同样, $ watch 方法期望的第

  • 本文向大家介绍node.js 如何监视文件变化,包括了node.js 如何监视文件变化的使用技巧和注意事项,需要的朋友参考一下 fs.FSWatcher fs.FSWatcher类 继承了 EventEmitter,用于监视文件变化,调用 fs.watch 后返回一个 fs.FSWatcher 实例,每当指定监视的文件被修改时,实例会触发事件调用回调函数 fs.watch() fs.watch(f

  • 为此,我使用spring-boot-starter-web-services(2.0.8.release)。我需要为来自遗留服务的SOAP响应添加度量标准(状态代码为200、非200等的请求数) 我的项目依赖于spring-boot-actuator,但不幸的是,我在actuator/千分尺文档中没有发现如何做到这一点。 是否可以为WebServiceTemplate启用度量标准,它实际上用于从远

  • 注意 许多监视器特性只在Neo4j服务器高级版和企业版才可以使用。 为了能获取Neo4j数据库的健康状况,可以采用不同级别的监控等级。这些功能一般都是通过 JMX呈现出来。 25.1. 调整远程JMX访问Neo4j的服务器 默认情况下,Neo4j高级版和企业版都不允许远程的JMX连接,因为在 conf/neo4j-wrapper.conf配置文件中的相关配置是被注释掉了的。为了启用该功能, 你必须

  • 问题内容: 我想在AngularJS服务中监听窗口事件,以便可以将它们广播到我的控制器。 我有一个Chrome扩展程序,可以使用发送任何消息。 我希望我的angularjs服务侦听该消息并将其发送到使用 在我的服务内部,我正在尝试通过以下侦听器这样做。 我也尝试过,但是我不知道为什么上面的代码不起作用。同样是我的IDE,jetbrains webstorms将上述代码片段归类为不可访问。 在此之前