sử dụng $ http bên trong nhà cung cấp tùy chỉnh trong cấu hình ứng dụng, angle.js


90

Câu hỏi chính - là nó có thể? Tôi đã cố gắng nhưng không may mắn ..

app.js chính

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

}]);
...

chính nhà cung cấp

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

Và tôi đã gặp lỗi như vậy:

Uncaught Error: Unknown provider: $http from services 

Bất kỳ ý tưởng?

Cảm ơn!



người đàn ông, yeah đó là sự thật, nhưng tôi đang nói về app.configphần
Kosmetika


tôi cũng biết về hạn chế này nhưng nghĩ rằng nhà cung cấp bên trong nó có thể bằng cách nào đó ..
Kosmetika

Câu trả lời:


158

Điểm mấu chốt là:

  • Bạn KHÔNG THỂ đưa một dịch vụ vào phần cấu hình nhà cung cấp .
  • Bạn CÓ THỂ đưa một dịch vụ vào phần khởi tạo dịch vụ của nhà cung cấp .

Chi tiết:

Angular framework có quá trình khởi tạo 2 giai đoạn:

GIAI ĐOẠN 1: Cấu hình

Trong configgiai đoạn này, tất cả các trình cung cấp được khởi tạo và tất cả các configphần được thực thi. Các configphần có thể chứa mã định cấu hình các đối tượng trình cung cấp và do đó chúng có thể được đưa vào các đối tượng trình cung cấp. Tuy nhiên, vì nhà cung cấp là nhà máy cho các đối tượng dịch vụ và ở giai đoạn này, nhà cung cấp chưa được khởi tạo / cấu hình đầy đủ -> bạn không thể yêu cầu nhà cung cấp tạo dịch vụ cho bạn ở giai đoạn này -> ở giai đoạn cấu hình bạn không thể sử dụng / dịch vụ tiêm . Khi giai đoạn này hoàn thành, tất cả các nhà cung cấp đã sẵn sàng (không thể thực hiện thêm cấu hình nhà cung cấp nào sau khi giai đoạn cấu hình hoàn thành).

GIAI ĐOẠN 2: Chạy

Trong suốt rungiai đoạn, tất cả các runphần được thực hiện. Ở giai đoạn này, các nhà cung cấp đã sẵn sàng và có thể tạo ra các dịch vụ -> trong rungiai đoạn này, bạn có thể sử dụng / tiêm dịch vụ .

Ví dụ:

1. Tiêm $httpdịch vụ vào chức năng khởi tạo trình cung cấp SẼ KHÔNG hoạt động

//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;
    };
});

Vì chúng tôi đang cố gắng đưa $httpdịch vụ vào một hàm được thực thi trong configgiai đoạn này, chúng tôi sẽ gặp lỗi:

Uncaught Error: Unknown provider: $http from services 

Lỗi này thực sự nói lên rằng $httpProvidercái được sử dụng để tạo $httpdịch vụ vẫn chưa sẵn sàng (vì chúng tôi vẫn đang trong configgiai đoạn).

2. Đưa $httpdịch vụ vào chức năng khởi tạo dịch vụ SẼ hoạt động:

//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;
    };
});

Vì bây giờ chúng ta đang đưa dịch vụ vào hàm khởi tạo dịch vụ, hàm này được thực thi trong rungiai đoạn mã này sẽ hoạt động.


63
Câu trả lời hay, nhưng trong khi nó giải thích cách không thể đưa các dịch vụ vào trong khi cấu hình, nó không giải thích cách tạo HTTP POST / GET trong khi cấu hình. Điều này quan trọng đối với các ứng dụng được cấu hình bằng các giá trị do API cung cấp.
Sean O'Dell

3
@bebraw & Kosmetika - Điều duy nhất tôi có thể nghĩ rằng bạn sẽ cần yêu cầu trong giai đoạn cấu hình là một số loại đối tượng cài đặt. Có thể nó chứa điểm cuối API, thông tin người dùng, cài đặt ngôn ngữ và ngôn ngữ của người dùng, v.v. Nếu đúng như vậy, tôi khuyên bạn nên đưa thông tin đó vào nguồn javascript bằng cách nào đó. Bạn có thể sử dụng kết xuất phía máy chủ trên index.html để đưa một số cài đặt vào để chúng có sẵn trước khi ứng dụng của bạn khởi chạy. Mọi thứ khác, tôi muốn cố gắng tìm ra cách để làm điều đó sau khi init
Sean Clark Hess

2
@Sean: Cách tạo HTTP POST / GET là một câu hỏi khác với câu hỏi của OP (Có thể sử dụng $ http trong giai đoạn cấu hình không?), Và có lẽ hoàn toàn xứng đáng với một bài đăng riêng biệt; do tính chất đồng bộ của giai đoạn cấu hình Angular, một cách tốt để cung cấp dữ liệu phía máy chủ cho mã cấu hình của bạn là hiển thị nó dưới dạng một đối tượng javascript trong trang HTML của bạn trong quá trình hiển thị phía máy chủ (ví dụ <script>var config = <% = mySettings.toJson() %>;</script>:). Điều này có thể được thực hiện bằng cách sử dụng một công cụ tạo khuôn mẫu như Smarty cho PHP, Jinja2 cho Python, Nunchucks cho NodeJS, v.v.
Trevor

4
@threed: Chèn dữ liệu cấu hình trực tiếp vào HTML hoặc js trên máy chủ chỉ hoạt động nếu mã máy khách của bạn đến từ cùng một máy chủ. Với CORS, giờ đây có thể (và rất mong muốn) mã máy khách được phân phát từ một máy chủ khác và dữ liệu được cung cấp từ (các) máy chủ riêng biệt. Trong những trường hợp đó, chúng tôi cần truy xuất dữ liệu cấu hình bằng HTTP.
Bernard

4
Trong khi đây là một câu trả lời, nó không phải là câu trả lời cho câu hỏi đã được đặt ra.
Eric

64

Điều này có thể cung cấp cho bạn một chút đòn bẩy:

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

Nhưng hãy cẩn thận, các lệnh gọi lại thành công / lỗi có thể khiến bạn ở trong tình trạng chạy đua giữa khởi động ứng dụng và phản hồi của máy chủ.


6
"Câu trả lời được chấp nhận" không thành công cho nhà cung cấp của tôi ... Tôi đã dành 2 ngày thất vọng để cố gắng làm cho nó hoạt động mà không có hy vọng. Cách tiếp cận của bạn đã hiệu quả ngay lập tức.
Dave Alperovich

Bạn có thể làm rõ liệu trường hợp được tạo ở đây là singleton dịch vụ "thực" hay chỉ là một bản sao của dịch vụ bị loại bỏ khi Angular thực hiện phép thuật bơm thực sự của nó.
Eric

Eric, tôi không thể xác nhận điều đó vào lúc này. Tuy nhiên, điều tôi thường làm (nếu có) là angular.injector(['mymodule'])- nhưng tôi không chắc liệu bạn có thể sử dụng phương pháp này cho $httpdịch vụ hay không. Tôi muốn nói rằng tôi có mặc dù. Không chắc liệu điều này có giúp ích hay không: - /
Cody

2
Đây phải là câu trả lời được chấp nhận. Tôi đã đấu tranh rất nhiều trong khi cố gắng làm cho nó hoạt động và cách tiếp cận này đã giải quyết được vấn đề của tôi ngay lập tức. Tôi nghĩ rằng đây có thể là một vấn đề rất phổ biến. Cảm ơn
@Cody

5
Tôi xác nhận rằng giải pháp được chấp nhận không hoạt động khi sử dụng $ http trong nhà cung cấp. Nhưng @Cody 's câu trả lời không làm các trick
Dino

1

Đây là một câu hỏi cũ, có vẻ như chúng ta đang có một số vấn đề về quả trứng gà nếu chúng ta muốn dựa vào khả năng cốt lõi của thư viện.

Thay vì giải quyết vấn đề một cách cơ bản, những gì tôi đã làm là vượt qua. Tạo một chỉ thị bao bọc toàn bộ cơ thể. Ví dụ.

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

Bây giờ mc-bodycần được khởi tạo trước khi hiển thị (một lần), ví dụ:

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

Auth là một dịch vụ hoặc nhà cung cấp, ví dụ:

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

Có vẻ như với tôi rằng tôi có quyền kiểm soát thứ tự của bootstrap, đó là sau khi bootstrap thông thường giải quyết tất cả cấu hình của nhà cung cấp và sau đó cố gắng khởi tạo mc-bodychỉ thị.

Và đối với tôi, chỉ thị này dường như có thể đi trước định tuyến, bởi vì định tuyến cũng được đưa vào thông qua một ví dụ chỉ thị. <ui-route />. Nhưng tôi có thể sai về điều này. Cần điều tra thêm.


Bạn có thể vui lòng nói rõ hơn về giải pháp của bạn?
Đánh dấu

-2

Để trả lời câu hỏi của bạn, "Có ý tưởng nào không?", Tôi sẽ trả lời là "có". Nhưng xin chờ chút nữa!

Tôi đề nghị chỉ sử dụng JQuery trong cấu hình. Ví dụ:

var app = angular.module('myApp', ['services']);
app.config(['$anyProvider', function ($anyProvider) {
    $.ajax({
        url: 'www.something.com/api/lolol',
        success: function (result) {
            $anyProvider.doSomething(result);
        }
    });
}]);

$ customProvider trong lần gọi lại thành công bao gồm $ như thể nó là một nhà cung cấp nội bộ.
Jeff Fischer,

1
Bạn nói đúng rằng tôi đã kết hợp $ và không- $. Tôi đã cập nhật tất cả thành $.
Suamere
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.