3

我需要做的就是下载一个 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/provider/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

4 回答 4

12

您永远不能将服务实例注入配置函数或提供程序,因为它们尚未配置。提供程序的存在是为了在注入特定服务之前对其进行配置。这意味着,某项服务总是有相应的提供者。为了澄清起见,这里有一个$location使用以下配置服务的小示例$locationProvider

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

所以这里发生的事情是,我们将$location服务配置为使用它的 html5mode。我们通过使用提供的接口来做到这一点$locationProvider。在config()执行时,还没有任何服务实例可用,但是您有机会在任何服务被实例化之前对其进行配置。

稍后在运行时(最早的时刻是run()函数),您可以注入服务。注入服务时你得到的是它的 providers$get()方法返回的东西。这也意味着,每个提供者都必须有一个$get()函数,否则$injector会引发错误。

但是,当创建自定义服务而不构建提供程序时会发生什么?所以像:

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

您不必关心,因为 Angular 会为您完成。每次您注册任何类型的服务时(除非它不是提供者),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 */
});

希望这能让事情变得清楚。

于 2013-09-13T20:21:17.957 回答
3

由于所有服务都是 Angular 中的单例,因此您可以使用 $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
})
于 2013-09-13T18:41:58.920 回答
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;
            }
        }
    }

}
});
于 2013-09-13T18:14:23.890 回答
0

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

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

初始化控制器:

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;

F类工厂

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

    categories: [],
    ....
  };

  return service;
});
于 2013-09-14T01:39:43.877 回答