将当前范围传递给AngularJS服务


106

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

我处于一种$ service的状态,知道它仅由一个控制器使用,我想在$ service方法本身中引用该控制器的作用域。

这在哲学上是正确的吗?

还是最好将事件广播到$ rootScope,然后让我的控制器侦听它们?


1
您能否让我们更具体地知道您要做什么?也许根本没有必要将范围扩大到服务上?
ganaraj 2013年

好吧,这并不难。简而言之,我希望能够访问$scope属性并$scope.$apply在需要时调用。
SC

另外,说我想将来自$ service的更改应用于$ scope。希望现在更加清楚。
SC

8
我建议您将希望服务访问的$ scope属性放到服务本身中(而不是将其包含在控制器中)。服务是比控制器更好的存储模型/数据的地方。
Mark Rajcok

@MarkRajcock我也试图了解此问题。目前,我只是在调用服务并将提供的数据附加到控制器的$scope...控制器将如何直接访问服务中的数据并将其传递给视图而不执行此操作?
drjimmie1976 2014年

Answers:


67

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

要触发$apply,您不需要作用域,可以调用$rootScope.$apply,因为在特定作用域或根目录中调用它没有区别。

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


我认为这是更好地解决我的AngularJS初学者疑问的答案。
SC

@Caio Cunha您能解释一下为什么通过范围不是一个好主意吗?我正好遇到这个问题,我想$scope通过使用异步executeSql()函数调用服务来添加一些东西。查看3个选项(1)在async函数上使用回调,然后调用$scope.$apply...这是可行的,但是很难看(2)传递$scope给async函数,然后调用theScope.$apply()...这也可以工作(3)使用promise。 ..尚未尝试过。为什么诺言是最好的方法?谢谢!
drjimmie1976

15

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

控制器的任务是操纵特定模型,而服务应处理全局任务。我宁愿坚持这种范式,而不要混淆一切。

这就是文档所说的

服务

Angular服务是单例,执行Web应用程序共有的特定任务

控制者

在Angular中,控制器是JavaScript函数(类型/类),用于扩展除根范围之外的angular Scope实例。

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


2
谢谢。很好的答复。深入了解我的情况,关键是我正在使用Service,因为我想要一个单例。只有一个控制器在使用该服务,但是可以在应用程序生命周期中多次实例化该控制器,因此我确实希望该服务始终处于相同状态。
SC

无论如何,对调用$apply$digest对$ rootScope 的澄清对我来说都是完全有意义的。
SC

1
我仍然将其单独保存到服务中进行测试。
bluehallu 2014年

如果功能是特定于控制器的一个实例的,则可以跳过实现服务的步骤,但否则,则不会,因为您牺牲了在这些实例之间共享状态的能力。此外,仅仅因为现在有一种类型的控制器,并不意味着明天就不会有其他控制器可以利用该功能。此外,服务可以避免使控制器膨胀。因此,问题不仅仅在于是否存在单个控制器,而在于功能是什么。
尼克

9

是。初始化$ 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
+1,但是,我想看到一种方法,$scope只要给定控制器注入服务,它就会自动知道每个控制器的状态-从而不必在服务上调用方法并手动将$scope其传递给它。
科迪2014年

2
@Cody我不建议,因为它是矛盾的依赖注入
Coldstar

同意,+ 1击落我!也许屠夫DIP也有-我会说,有冗余的风险。
科迪2015年

您在这里与工厂混合服务。此解决方案使用与服务不同的工厂。主要区别在于服务返回一个(单个)对象。而工厂返回的函数可以实例化(new MyFunction())。问题是关于服务,在这种new情况下无法进行呼叫。
卡瓦帕洛2015年

@Karvapallo好点。作为对策,我认为角度服务是指工厂,服务和提供者(ng-wat)?
2015年

6

我个人认为传递$scope给服务不是一个好主意,因为它会创建某种循环引用:控制器取决于服务,而服务取决于控制器的范围。

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

我的首选方法是将域对象放入控制器范围,并将其传递给服务。这样,无论服务是在控制器内部还是将来在其他服务中使用,该服务都可以工作。

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

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

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

我永远都不想使用广播$apply和/或类似的东西,因为恕我直言,良好的面向对象实践总是会胜过任何Angular-magic。


1
此代码与此代码有什么区别吗?:$scope.errors = []; $scope.myService = new MyService($scope.errors);
Soldeplata Saketos

@SoldeplataSaketos-是的。errors独立生活$scope。这就是答案的重点。请检查我在文本中提供的链接。干杯。
Marco Faustinelli

1
如果我正确理解您的代码,$scope.errors则指向var errors,而变量错误对我来说似乎是多余的,因为它只是另一个指针。我可以想到的一种类似情况是,这段代码很明显是多余的:const errors = errors2 = errors3 = []; $scope.errors = errors;。您是否同意仅使用您提供的这段代码似乎var errors = []是多余的?
Soldeplata Saketos

不,这不对。我一遍又一遍地重复自己:errors独立生活$scope。您需要了解什么是域对象,以及什么是var赋值。如果我提供的链接不够用,那么还有很多其他可用的材料。
Marco Faustinelli

好吧,这将完全取决于函数的实现MyService(errors)。据我了解,该服务应基于参数(在本例中为指针)生成日志记录数组。对我来说,这是一个糟糕的模式,因为服务是单角度的。如果服务的实现编程良好,则应在内部变量中生成数组(以保持单例状态)。因此,没有必要在服务外部初始化变量。
Soldeplata Saketos
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.