在应用程序配置中的自定义提供程序中使用 $http,angular.js

IT技术 javascript angularjs angular-services
2021-02-07 17:48:20

主要问题 - 有可能吗?我试过没有运气..

主应用程序.js

...
var app = angular.module('myApp', ['services']);
app.config(['customProvider', function (customProvider) {

}]);
...

提供者本身

var services = angular.module('services', []);
services.provider('custom', function ($http) {
});

我有这样的错误:

Uncaught Error: Unknown provider: $http from services 

有任何想法吗?

谢谢!

4个回答

底线是:

  • 不能将服务注入提供者配置部分
  • CAN注入服务成初始化提供者的服务的部分

细节:

Angular 框架有一个 2 阶段的初始化过程:

阶段 1:配置

在这个config阶段,所有的提供者都被初始化,所有的config部分都被执行。这些config部分可能包含配置提供者对象的代码,因此它们可以被注入提供者对象。但是,由于提供者是服务对象的工厂,并且在此阶段提供者尚未完全初始化/配置 -> 在此阶段您不能要求提供者为您创建服务 -> 在配置阶段您不能使用/注入服务当这个阶段完成时,所有的提供者都准备好了(配置阶段完成后不能再做更多的提供者配置)。

阶段 2:运行

run阶段期间,所有run部分都被执行。在此阶段,提供者已准备就绪,可以创建服务 -> 在此run阶段,您可以使用/注入服务

例子:

1. 将$http服务注入提供者初始化函数不起作用

//ERRONEOUS
angular.module('myModule').provider('myProvider', function($http) {
    // SECTION 1: code to initialize/configure the PROVIDER goes here (executed during `config` phase)
    ...

    this.$get = function() {
        // code to initialize/configure the SERVICE goes here (executed during `run` stage)

        return myService;
    };
});

由于我们试图将$http服务注入到在该config阶段执行的函数中,我们将得到一个错误:

Uncaught Error: Unknown provider: $http from services 

这个错误实际上是说$httpProvider用于创建$http服务的 尚未准备好(因为我们仍处于config阶段)。

2.注射$http服务,以服务初始化函数WILL工作:

//OK
angular.module('myModule').provider('myProvider', function() {
    // SECTION 1: code to initialize/configure the PROVIDER goes here (executed during `config` phase)
    ...

    this.$get = function($http) {
        // code to initialize/configure the SERVICE goes here (executed during `run` stage)

        return myService;
    };
});

由于我们现在将服务注入到服务初始化函数中,该函数在run阶段执行,此代码将起作用。

很好的答案,但虽然它解释了如何在配置期间无法注入服务,但它没有解释如何在配置期间进行 HTTP POST/GET。这对于使用 API 提供的值配置的应用程序很重要。
2021-03-21 17:48:20
虽然这是一个答案,但它不是所问问题的答案。
2021-03-22 17:48:20
@Sean:如何制作 HTTP POST/GET 是一个与 OP 不同的问题(是否可以在配置阶段使用 $http?),并且可能完全值得单独发表一篇文章;由于 Angular 配置阶段的同步特性,向您的配置代码提供服务器端数据的一个好方法是在服务器端呈现期间将其呈现为 HTML 页面中的 javascript 对象(例如<script>var config = <% = mySettings.toJson() %>;</script>)。这可以使用模板引擎来完成,例如用于 PHP 的 Smarty、用于 Python 的 Jinja2、用于 NodeJS 的 Nunchucks 等。
2021-03-31 17:48:20
@threed:仅当您的客户端代码来自同一服务器时,将配置数据直接插入服务器上的 HTML 或 js 中才有效。使用 CORS,现在可以(并且非常可取)从不同的服务器提供客户端代码,并从单独的服务器提供数据。在这些情况下,我们确实需要使用 HTTP 检索配置数据。
2021-03-31 17:48:20
@bebraw & Kosmetika - 我认为您在配置阶段唯一需要请求的是某种设置对象。也许它包含 API 端点、用户信息、用户的区域设置和语言设置等。如果是这种情况,我建议以某种方式将这些信息包含在 javascript 源中。您可以在 index.html 上使用服务器端呈现来放入一些设置,以便在您的应用程序初始化之前它们可用。其他一切,我会尝试弄清楚如何在初始化后进行
2021-04-02 17:48:20

这可能会给你一点影响力:

var initInjector = angular.injector(['ng']);
var $http = initInjector.get('$http');

但要小心,成功/错误回调可能会使您处于应用程序启动和服务器响应之间的竞争状态。

我确认接受的解决方案不适用于在提供程序中使用 $http。但@Cody 的回答确实成功了
2021-03-23 17:48:20
我的提供者的“接受的答案”失败了……我花了 2 天的时间沮丧地试图使这项工作毫无希望。你的方法立即奏效。
2021-03-26 17:48:20
您能否澄清这里创建的实例是“真正的”服务单例,还是只是在 Angular 执行其真正的注入器魔法时被丢弃的服务实例。
2021-03-26 17:48:20
这应该是公认的答案。我在尝试让它工作时挣扎了很久,这种方法立即解决了我的问题。我认为这可能是一个非常普遍的问题。谢谢@Cody
2021-03-28 17:48:20
埃里克,我现在无法确认。但是,我通常做的(如果适用)是angular.injector(['mymodule'])- 但我不确定您是否可以将这种方法用于$http服务。我想说我有。不确定这是否有帮助:-/
2021-04-02 17:48:20

这是一个老问题,如果我们想依赖库的核心能力,似乎我们有一些鸡蛋的事情要做。

我所做的不是从根本上解决问题,而是绕过。创建一个包裹整个身体的指令。前任。

<body ng-app="app">
  <div mc-body>
    Hello World
  </div>
</body>

现在mc-body需要在渲染之前初始化(一次),例如。

link: function(scope, element, attrs) {
  Auth.login().then() ...
}

Auth 是服务或提供者,例如。

.provider('Auth', function() {
  ... keep your auth configurations
  return {
    $get: function($http) {
      return {
        login: function() {
          ... do something about the http
        }
      }
    }
  }
})

在我看来,我确实可以控制引导程序的顺序,这是在常规引导程序解析所有提供程序配置然后尝试初始化mc-body指令之后。

而且这个指令在我看来可以在路由之前,因为路由也是通过一个指令 ex 注入的。<ui-route />. 但我可能是错的。需要更多的调查。

你能详细说明你的解决方案吗?
2021-04-08 17:48:20

在回答您的问题“有什么想法吗?”时,我会回答“是”。但是等等,还有更多!

我建议只在配置中使用 JQuery。例如:

var app = angular.module('myApp', ['services']);
app.config(['$anyProvider', function ($anyProvider) {
    $.ajax({
        url: 'www.something.com/api/lolol',
        success: function (result) {
            $anyProvider.doSomething(result);
        }
    });
}]);
你是对的,我混合了 $ 和非 $。我将其更新为全部为 $.
2021-03-29 17:48:20
成功回调中的 $customProvider 包含 $ 就好像它是一个内部提供程序一样。
2021-04-06 17:48:20