将 $scope 注入 Angular 服务函数() [英] Injecting $scope into an angular service function()

查看:13
本文介绍了将 $scope 注入 Angular 服务函数()的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个服务:

angular.module('cfd')
  .service('StudentService', [ '$http',
    function ($http) {
    // get some data via the $http
    var path = 'data/people/students.json';
    var students = $http.get(path).then(function (resp) {
      return resp.data;
    });     
    //save method create a new student if not already exists
    //else update the existing object
    this.save = function (student) {
      if (student.id == null) {
        //if this is new student, add it in students array
        $scope.students.push(student);
      } else {
        //for existing student, find this student using id
        //and update it.
        for (i in students) {
          if (students[i].id == student.id) {
            students[i] = student;
          }
        }
      }
    };

但是当我调用save()时,我无法访问$scope,并得到ReferenceError: $scope is not defined.因此(对我而言)合乎逻辑的步骤是为 save() 提供 $scope,因此我还必须将其提供/注入到 service.所以如果我这样做:

But when I call save(), I don't have access to the $scope, and get ReferenceError: $scope is not defined. So the logical step (for me), is to provide save() with the $scope, and thus I must also provide/inject it to the service. So if I do that like so:

  .service('StudentService', [ '$http', '$scope',
                      function ($http, $scope) {

我收到以下错误:

错误:[$injector:unpr] 未知提供者:$scopeProvider <- $scope <-学生服务

Error: [$injector:unpr] Unknown provider: $scopeProvider <- $scope <- StudentService

错误中的链接(哇,太棒了!)让我知道它与注入器相关,并且可能与 js 文件的声明顺序有关.我已经尝试在 index.html 中重新排序它们,但我认为它更简单,例如我注入它们的方式.

The link in the error (wow that is neat!) lets me know it is injector related, and might have to do with order of declaration of the js files. I have tried reordering them in the index.html, but I think it is something more simple, such as the way I am injecting them.

使用 Angular-UI 和 Angular-UI-Router

Using Angular-UI and Angular-UI-Router

推荐答案

你看到注入控制器的 $scope 不是某种服务(像其他可注入的东西一样),而是范围对象.可以创建许多范围对象(通常原型继承自父范围).所有作用域的根是 $rootScope,您可以使用任何作用域的 $new() 方法(包括 $rootScope).

The $scope that you see being injected into controllers is not some service (like the rest of the injectable stuff), but is a Scope object. Many scope objects can be created (usually prototypically inheriting from a parent scope). The root of all scopes is the $rootScope and you can create a new child-scope using the $new() method of any scope (including the $rootScope).

Scope 的目的是将应用程序的表示和业务逻辑粘合在一起".将 $scope 传递给服务没有多大意义.

The purpose of a Scope is to "glue together" the presentation and the business logic of your app. It does not make much sense to pass a $scope into a service.

服务是用于(除其他外)共享数据(例如在多个控制器之间)并通常封装可重用代码片段的单例对象(因为它们可以被注入并在需要它们的应用程序的任何部分提供它们的服务"): 控制器、指令、过滤器、其他服务等).

Services are singleton objects used (among other things) to share data (e.g. among several controllers) and generally encapsulate reusable pieces of code (since they can be injected and offer their "services" in any part of your app that needs them: controllers, directives, filters, other services etc).

我敢肯定,各种方法都适合您.一个是这样的:
由于 StudentService 负责处理学生数据,您可以让 StudentService 保存一组学生,并让它与任何可能感兴趣的人共享"它(例如你的 $scope).如果有其他需要访问该信息的视图/控制器/过滤器/服务(如果现在没有,如果它们很快开始弹出,请不要感到惊讶),这更有意义.
每次添加新学生时(使用服务的 save() 方法),服务自己的学生数组将被更新,并且共享该数组的所有其他对象也将自动更新.

I am sure, various approaches would work for you. One is this:
Since the StudentService is in charge of dealing with student data, you can have the StudentService keep an array of students and let it "share" it with whoever might be interested (e.g. your $scope). This makes even more sense, if there are other views/controllers/filters/services that need to have access to that info (if there aren't any right now, don't be surprised if they start popping up soon).
Every time a new student is added (using the service's save() method), the service's own array of students will be updated and every other object sharing that array will get automatically updated as well.

根据上述方法,您的代码可能如下所示:

Based on the approach described above, your code could look like this:

angular.
  module('cfd', []).

  factory('StudentService', ['$http', '$q', function ($http, $q) {
    var path = 'data/people/students.json';
    var students = [];

    // In the real app, instead of just updating the students array
    // (which will be probably already done from the controller)
    // this method should send the student data to the server and
    // wait for a response.
    // This method returns a promise to emulate what would happen 
    // when actually communicating with the server.
    var save = function (student) {
      if (student.id === null) {
        students.push(student);
      } else {
        for (var i = 0; i < students.length; i++) {
          if (students[i].id === student.id) {
            students[i] = student;
            break;
          }
        }
      }

      return $q.resolve(student);
    };

    // Populate the students array with students from the server.
    $http.get(path).then(function (response) {
      response.data.forEach(function (student) {
        students.push(student);
      });
    });

    return {
      students: students,
      save: save
    };     
  }]).

  controller('someCtrl', ['$scope', 'StudentService', 
    function ($scope, StudentService) {
      $scope.students = StudentService.students;
      $scope.saveStudent = function (student) {
        // Do some $scope-specific stuff...

        // Do the actual saving using the StudentService.
        // Once the operation is completed, the $scope's `students`
        // array will be automatically updated, since it references
        // the StudentService's `students` array.
        StudentService.save(student).then(function () {
          // Do some more $scope-specific stuff, 
          // e.g. show a notification.
        }, function (err) {
          // Handle the error.
        });
      };
    }
]);

<小时>

<子>使用这种方法时您应该注意的一件事是永远不要重新分配服务的数组,因为这样任何其他组件(例如范围)仍将引用原始数组并且您的应用程序将中断.
例如.清除 StudentService 中的数组:

/* DON'T DO THAT   */  
var clear = function () { students = []; }

/* DO THIS INSTEAD */  
var clear = function () { students.splice(0, students.length); }

另请参阅此简短演示.

小更新:

几句话以避免在谈论使用服务时可能出现的混淆,而不是使用 service() 函数创建它.

A few words to avoid the confusion that may arise while talking about using a service, but not creating it with the service() function.

引用 关于 $provide 的文档:

Angular 服务是由服务工厂创建的单例对象.这些服务工厂是由服务提供者创建的功能.服务提供者是构造函数.实例化时,它们必须包含一个名为 $get 的属性,该属性包含 服务工厂 函数.
[...]
... $provide 服务有额外的帮助方法来注册服务而不指定提供者:

An Angular service is a singleton object created by a service factory. These service factories are functions which, in turn, are created by a service provider. The service providers are constructor functions. When instantiated they must contain a property called $get, which holds the service factory function.
[...]
...the $provide service has additional helper methods to register services without specifying a provider:

  • provider(provider) - 向 $injector 注册服务提供者
  • constant(obj) - 注册一个可以被提供者和服务访问的值/对象.
  • value(obj) - 注册一个只能由服务访问的值/对象,而不是提供者.
  • factory(fn) - 注册一个服务工厂函数 fn,它将被包装在一个服务提供者对象中,其 $get 属性将包含给定的工厂函数.
  • service(class) - 注册一个构造函数,该类将被包装在一个服务提供者对象中,其 $get 属性将使用给定的构造函数实例化一个新对象.
  • provider(provider) - registers a service provider with the $injector
  • constant(obj) - registers a value/object that can be accessed by providers and services.
  • value(obj) - registers a value/object that can only be accessed by services, not providers.
  • factory(fn) - registers a service factory function, fn, that will be wrapped in a service provider object, whose $get property will contain the given factory function.
  • service(class) - registers a constructor function, class that will be wrapped in a service provider object, whose $get property will instantiate a new object using the given constructor function.

基本上,它说的是每个 Angular 服务都是使用 $provide.provider() 注册的,但是对于更简单的服务有快捷方式"方法(其中两个是 service()factory()).
这一切都归结为"服务,因此您使用哪种方法并没有太大区别(只要该方法可以满足您的服务要求).

Basically, what it says is that every Angular service is registered using $provide.provider(), but there are "shortcut" methods for simpler services (two of which are service() and factory()).
It all "boils down" to a service, so it doesn't make much difference which method you use (as long as the requirements for your service can be covered by that method).

顺便说一句,provider vs service vs factory 是 Angular 新手最容易混淆的概念之一,但幸运的是有很多资源(此处为 SO)以使事情变得更容易.(随便搜索一下.)

BTW, provider vs service vs factory is one of the most confusing concepts for Angular new-comers, but fortunately there are plenty of resources (here on SO) to make things easier. (Just search around.)

(我希望能解决这个问题 - 如果没有,请告诉我.)

(I hope that clears it up - let me know if it doesn't.)

这篇关于将 $scope 注入 Angular 服务函数()的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆