【问题标题】:Passing current scope to an AngularJS Service将当前范围传递给 AngularJS 服务
【发布时间】:2013-03-08 17:10:39
【问题描述】:

将“当前”$scope 传递给 AngularJS 服务是否正确?

我有一个 $service 知道它只被一个控制器使用的情况,我想在 $service 方法本身中引用控制器的范围。

哲学上正确吗?

或者我最好将事件广播到 $rootScope,然后让我的控制器监听它们?

【问题讨论】:

  • 您能否更具体地告诉我们您正在尝试做什么?也许根本不需要将范围推到服务上?
  • 嗯,这并不难。简单地说,我希望能够访问$scope 属性并在需要时调用$scope.$apply
  • 另外,假设我想将来自 $service 的更改应用到 $scope。希望现在更清楚了。
  • 我建议您将希望服务访问的 $scope 属性放入服务本身(而不是将它们放在控制器中)。服务是比控制器更好的存储模型/数据的地方。
  • @MarkRajcock 我也在尝试理解这个问题。目前我只是调用一个服务并将提供的数据附加到控制器的$scope...控制器如何直接访问服务中的数据并将其传递给视图而不这样做?

标签: angularjs data-binding angularjs-scope angular-services


【解决方案1】:

我个人认为将整个$scope 传递给服务是一个坏主意,因为它创建了一种循环引用:控制器依赖于服务,服务依赖于范围控制器。

除了在关系方面令人困惑之外,像这样的事情最终会妨碍垃圾收集器。

我的首选方法是将domain object 放在控制器范围内并将其传递给服务。无论是在控制器内部使用,还是将来在另一个服务内部使用,服务都可以这样工作。

例如,如果服务应该从数组errors 中推送和弹出元素,我的代码将是:

var errors = [];
$scope.errors = errors;
$scope.myService = new MyService(errors);

然后服务通过在errors 上操作与控制器进行交互。 当然,我必须小心不要清除整个数组引用,但归根结底,这是 JS 普遍关心的问题。

我永远不想使用广播、$apply 和/或类似的东西,因为恕我直言,好的 OO 实践总是胜过任何 Angular 魔法。

【讨论】:

  • 这段代码和这个有区别吗?:$scope.errors = []; $scope.myService = new MyService($scope.errors);
  • @SoldeplataSaketos - 是的,确实如此。 errors 独立于 $scope 生活。这就是这个答案的重点。请检查我在文本中提供的链接。干杯。
  • 如果我理解你的代码,$scope.errors 指向var errors,变量errors 对我来说是多余的,因为它只是另一个指针。我能想到的一种类似情况,它明显是多余的,这是一段代码:const errors = errors2 = errors3 = []; $scope.errors = errors;。您是否同意仅凭您提供的那段代码,var errors = [] 似乎是多余的?
  • 不,不是。我逐字重复自己:errors 独立于$scope 生活。您需要了解域对象是什么,以及var 分配是什么。如果我提供的链接不够用,还有很多其他可用的材料。
  • 嗯,这将完全取决于函数 MyService(errors) 的实现。据我了解,该服务应该根据参数(在本例中为指针)生成一个日志记录数组。对我来说,这是一个糟糕的模式,因为服务是有角度的单例。如果服务的实现编程良好,它应该在内部变量中生成数组(以保持单例)。因此,在服务之外初始化变量是没有意义的。
【解决方案2】:

是的。您可以在初始化时将 $scope 传递给服务。在服务构造函数中,您可以将范围分配给类似 this._scope 的内容,然后在服务中引用范围!

angular.module('blah').controller('BlahCtrl', function($scope, BlahService) {

    $scope.someVar = 4;

    $scope.blahService = new blahService($scope);

});

angular.module('blah').factory('blahService', function() {

    //constructor
    function blahService(scope) {
        this._scope = scope;

        this._someFunction()
    }

    //wherever you'd reference the scope
    blahService.prototype._someFunction = function() {

        this._scope['someVar'] = 5;

    }

    return blahService;

});

【讨论】:

  • +1,但是,我希望看到一种方法可以在给定控制器注入服务时自动知道每个控制器的 $scope —— 这样就不必在服务上调用方法并且手动将$scope 传递给它。
  • @Cody 我不建议这样做,因为它与依赖注入相矛盾
  • 同意,+1 击落我!也可能是屠夫 DIP——我会说,有被多余的风险。
  • 您在这里将服务与工厂混合在一起。该解决方案使用工厂,这与服务不同。主要区别在于服务返回一个(单例)对象。而工厂返回一个可以实例化的函数 (new MyFunction())。问题是关于一项服务,不能选择调用new
  • @Karvapallo 好点。作为反驳点,我认为角度服务指的是工厂、服务和提供者 (ng-wat)?
【解决方案3】:

要让控制器知道异步发生的时间,请使用Angular promises

要触发$apply,不需要作用域,可以调用$rootScope.$apply,在特定作用域和根中调用没有区别。

关于变量读数,如果你收到参数会更好。但是您也可以从作用域中将其作为对象参数读取,但我会使用参数,这将使您的服务接口更加清晰。

【讨论】:

  • 我认为这是更好地解决我的AngularJS初学者疑惑的答案。
  • @Caio Cunha 您能否详细说明为什么传递范围不是一个好主意?我遇到了这个问题,我想通过使用异步executeSql() 函数调用服务来向$scope 添加一些东西。查看 3 个选项 (1) 在 async 函数上使用回调,然后调用 $scope.$apply...这可行,但很难看 (2) 将 $scope 传递给 async 函数,然后调用 theScope.$apply()...this也有效(3)使用承诺......尚未尝试过。为什么承诺是最好的方式?谢谢!
【解决方案4】:

我会说,如果您的功能仅特定于一个控制器,而不是您不需要服务。

控制器的任务是操作特定的模型,而服务应该处理全局任务。我宁愿坚持这种范式,也不愿混为一谈。

这是文档所说的

服务

Angular 服务是执行 Web 应用常见的特定任务的单例

控制器

在 Angular 中,控制器是一个 JavaScript 函数(类型/类),用于增加 Angular Scope 的实例,不包括根范围。

PS:除此之外,如果您需要消化,您还可以在您的服务中注入 $rootScope。

【讨论】:

  • 谢谢。很好的回复。深入了解我的情况,关键是我使用 Service 是因为我想要一个单例。只有一个控制器在使用服务,但是这个控制器在应用生命周期中可能会被实例化多次,所以我真的希望服务始终处于相同的状态。
  • 无论如何,关于向 $rootScope 调用 $apply$digest 的说明对我来说完全有意义。
  • 我仍然会将其单独保存到服务中进行测试。
  • 如果功能是特定于控制器的一个 instance 的,那么您可以跳过实现服务,否则不行,因为您牺牲了在这些实例之间共享状态的能力。此外,仅仅因为今天只有一种类型的控制器,并不意味着明天不会有不同的控制器可以利用该功能。此外,服务可以避免使控制器膨胀。所以与其说是是否有一个控制器,不如说是功能是什么。
猜你喜欢
  • 2017-08-17
  • 2017-12-30
  • 1970-01-01
  • 2013-08-08
  • 2019-05-12
  • 1970-01-01
  • 2014-07-09
  • 2016-01-14
  • 2014-09-28
相关资源
最近更新 更多