如何直接将$ http注入提供者?

时间:2013-09-13 15:24:42

标签: angularjs

我需要做的就是下载一个json文件,并在设置路径后将其分配给OCategories提供程序中的PCategory。但是我收到$http不存在的错误。如何将其注入我的提供程序并在setPath函数内部下载?

var app = angular.module('NSApp',
    [
        'ui.bootstrap', 
        'MDItem', 
        'MDUser', 
        'MDNotification',
        'MDUpload'
    ]
);


app.config(function(PCategoriesProvider)
{
    PCategoriesProvider.setPath('data/csv/categories.json');
});

MDItem /提供者/ category.js

angular.module('MDItem').provider('PCategories',function(){
var OCategories; 
var OPath; 

return{
    setPath: function(d){
        OPath = d; 
        console.log('Path is set. Trying to download categories.');
        OCategories = $http.get(oPath);       

    },

    $get : function() {
        return {
            categories : OCategories
        }
    }

}

});

4 个答案:

答案 0 :(得分:13)

您永远不能将服务实例注入配置函数或提供程序,因为它们尚未配置。存在提供程序以在注入之前配置特定服务。这意味着,某个服务总是有相应的提供商。只是为了澄清,这是使用$location配置$locationProvider服务的一个小例子:

angular.module('myModule').config(function ($locationProvider) {
  $locationProvider.html5Mode(true);
});

所以这里发生的是,我们配置$location服务以使用其html5mode。我们通过使用$locationProvider提供的接口来实现这一点。在执行config()时,尚未提供任何服务实例,但您可以在实例化之前配置任何服务。

稍后在运行时(最早的时刻是run()函数),您可以注入服务。注入服务时获得的是其提供者$get()方法返回的内容。这也意味着,每个提供商都必须有$get()函数,否则$injector会抛出错误。

但是,在没有构建提供程序的情况下创建自定义服务会发生什么?如下所示:

angular.module('myModule').factory('myService', function () {
  ...
});

你只需要关心,因为角度适合你。每当您注册任何类型的服务时(除非它不是提供者),angular将为您设置一个$get()方法的提供者,因此$injector能够稍后实例化。

那么如何解决你的问题。如何在实际处于配置短语时使用$http服务进行异步调用?答案:你做不到。

您可以执行的操作是,只要您的服务被实例化,就会运行$http调用。因为在您的服务实例化时,您可以注入其他服务(就像您一直这样)。所以你实际上会做这样的事情:

angular.module('myModule').provider('custom', function (otherProvider, otherProvider2) {
  // some configuration stuff and interfaces for the outside world

  return {
    $get: function ($http, injectable2, injectable3) {
       $http.get(/*...*/);
    }
  };
});

现在,您的自定义提供程序返回一个具有$http依赖关系的服务实例。注入服务后,其所有依赖项也会被注入,这意味着在$get内您可以访问$http服务。接下来,您只需拨打电话即可。

要尽快调用此调用,您必须在run()短语中注入自定义服务,如下所示:

angular.module('myModule').run(function (custom, injectable2) {
  /* custom gets instantiated, so its $http call gets invoked */
});

希望这能使事情变得清晰。

答案 1 :(得分:3)

由于所有服务都是角度的单例,因此您可以使用$ http承诺在工厂中存储变量。然后在启动时调用工厂时它将下载json。

然后,您还可以在工厂中公开刷新数据的方法。

我知道这不是你问题的确切答案,但我想我会分享如何做到这一点。

angular.module('MDItem').factory('PCategories', function ($http, PCategoriesPath) {
  var service = {
    categories: [],
    get: function () {
      if (angular.isUndefined(PCategoriesPath)) {
        throw new Error('PCategoriesPath must be set to get items');
      }
      $http.get(PCategoriesPath).then(function (response) {
        service.categories = response.data;
      });
    }
  };

  // Get the categories at startup / or if you like do it later.
  service.get();

  return service;
});


// Then make sure that PCategoriesPath is created at startup by using const
angular.module('MDItem').const('PCategoriesPath', 'data/csv/categories.json');

angular.module('app').controller('myCtrl', function ($scope, PCategories) {
  $scope.categories = PCategories.categories;

  // And optionally, use a watch if you would like to do something if the categories are updated via PCategories.get()
  $scope.$watch('categories', function (newCategories) {
    console.log('Look maa, new categories');
  }, true); // Notice the true, which makes angular work when watching an array
})

答案 2 :(得分:2)

你必须在$ get函数中注入$ http,因为这是注入器调用的函数。

但是,要下载类别,最好使用promises

angular.module('MDItem').provider('PCategories',function(){
var OCategories; 
var OPath; 

return{
    setPath: function(d){
        OPath = d; 
        console.log('Path is set');    
    },

    $get : function($http) {
        return {
            fetch: function () {
                var deferred = $q.defer();
                $http.get(oPath).then(function (value) {
                    deferred.resolve(value);
                }
                return deferred.promise;
            }
        }
    }

}
});

答案 3 :(得分:0)

我用一种非常简单有效的不同方法实现了我想要的东西。只需在主index.html(NOT PARTIAL)中添加一个虚拟控制器。现在我的所有模块和控制器之间共享数据,所有内容都下载一次。 :)哦,我喜欢AJ。

...
<div ng-controller="initController" hidden></div>
...

initController:

angular.module('NSApp',[]).controller("initController",function($scope, $http, FCategory, FLocation){

    $http.get('data/json/categories.json').then(function (response) {
        FCategory.categories = response.data;
    });

    $http.get('data/json/cities.json').then(function (response) {
        FLocation.cities = response.data;
    });

    $http.get('data/json/regions.json').then(function (response) {
        FLocation.regions = response.data;
    });

});

现在你可以访问它了:

 angular.module('MDTest', []).controller("test",function($scope, FCategory, FLocation){

        $scope.categories = FCategory.categories;

FCategory工厂

    angular.module('MDItem').factory('FCategory', function ($http) {
  var service = {

    categories: [],
    ....
  };

  return service;
});