ใช้ $ http ภายในผู้ให้บริการที่กำหนดเองในการกำหนดค่าแอป angular.js


90

คำถามหลัก - เป็นไปได้ไหม? ฉันพยายามโดยไม่มีโชค ..

app 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 

ความคิดใด ๆ ?

ขอบคุณ!



ผู้ชายใช่มันเป็นเรื่องจริง แต่ฉันกำลังพูดถึงapp.configส่วนหนึ่ง
Kosmetika


ฉันยังรู้เกี่ยวกับข้อ จำกัด นี้ แต่คิดว่าผู้ให้บริการที่อยู่ภายในนั้นเป็นไปได้อย่างใด ..
Kosmetika

คำตอบ:


158

บรรทัดล่างคือ:

  • คุณไม่สามารถฉีดให้บริการในส่วนการตั้งค่าผู้ให้บริการ
  • คุณสามารถฉีดให้บริการในส่วนที่เริ่มต้นการให้บริการของผู้ให้บริการ

รายละเอียด:

กรอบเชิงมุมมีกระบวนการเริ่มต้น 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บริการไปยังฟังก์ชันการเริ่มต้นบริการจะทำงาน:

//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ขั้นตอนรหัสนี้จะทำงาน


63
คำตอบที่ดี แต่ในขณะที่อธิบายว่าไม่สามารถแทรกบริการระหว่างการกำหนดค่าได้อย่างไร แต่ก็ไม่ได้อธิบายวิธีสร้าง HTTP POST / GET ระหว่างการกำหนดค่า สิ่งนี้สำคัญสำหรับแอปพลิเคชันที่กำหนดค่าโดยใช้ค่าที่จัดเตรียมโดย API
Sean O'Dell

3
@bebraw & Kosmetika - สิ่งเดียวที่ฉันคิดว่าคุณจะต้องขอในช่วงการกำหนดค่าคือวัตถุการตั้งค่าบางประเภท อาจมีจุดสิ้นสุด API ข้อมูลผู้ใช้สถานที่ตั้งของผู้ใช้และการตั้งค่าภาษา ฯลฯ หากเป็นเช่นนั้นฉันขอแนะนำให้รวมข้อมูลนั้นในแหล่งที่มาของจาวาสคริปต์ คุณสามารถใช้การแสดงผลฝั่งเซิร์ฟเวอร์บน index.html เพื่อตั้งค่าบางอย่างเพื่อให้สามารถใช้งานได้ก่อนที่แอปของคุณจะเริ่มต้น อย่างอื่นฉันจะพยายามหาวิธีทำหลังเริ่มต้น
Sean Clark Hess

2
@Sean: วิธีสร้าง HTTP POST / GET เป็นคำถามที่แตกต่างจาก OP (เป็นไปได้ไหมที่จะใช้ $ http ในขั้นตอนการกำหนดค่า) และอาจใช้โพสต์แยกกันโดยสิ้นเชิง เนื่องจากลักษณะซิงโครนัสของเฟสคอนฟิกูเรชันของ Angular วิธีที่ดีในการให้ข้อมูลฝั่งเซิร์ฟเวอร์ไปยังโค้ดคอนฟิกูเรชันของคุณคือการแสดงผลเป็นวัตถุจาวาสคริปต์ในหน้า HTML ของคุณระหว่างการแสดงผลฝั่งเซิร์ฟเวอร์ (เช่น<script>var config = <% = mySettings.toJson() %>;</script>) สามารถทำได้โดยใช้เครื่องมือสร้างเทมเพลตเช่น Smarty สำหรับ PHP, Jinja2 สำหรับ Python, Nunchucks สำหรับ NodeJS เป็นต้น
Trevor

4
@threed: การแทรกข้อมูลการกำหนดค่าลงใน HTML หรือ js โดยตรงบนเซิร์ฟเวอร์จะทำงานได้ก็ต่อเมื่อรหัสไคลเอ็นต์ของคุณมาจากเซิร์ฟเวอร์เดียวกัน ด้วย CORS ตอนนี้เป็นไปได้ (และเป็นที่ต้องการมาก) ที่จะให้บริการรหัสไคลเอนต์จากเซิร์ฟเวอร์อื่นและข้อมูลถูกเสิร์ฟจากเซิร์ฟเวอร์ที่แยกจากกัน ในกรณีดังกล่าวเราจำเป็นต้องดึงข้อมูลการกำหนดค่าโดยใช้ HTTP
Bernard

4
แม้ว่านี่จะเป็นคำตอบ แต่ก็ไม่ใช่คำตอบสำหรับคำถามที่ถูกถาม
Eric

64

สิ่งนี้อาจทำให้คุณได้ประโยชน์เล็กน้อย:

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

แต่โปรดระวังการเรียกกลับสำเร็จ / ข้อผิดพลาดอาจทำให้คุณอยู่ในสภาพการแข่งขันระหว่างการเริ่มต้นแอปและการตอบสนองของเซิร์ฟเวอร์


6
"คำตอบที่ยอมรับ" ล้มเหลวสำหรับผู้ให้บริการของฉัน ... ฉันใช้เวลา 2 วันในการพยายามทำงานนั้นโดยไม่หวัง แนวทางของคุณได้ผลทันที
Dave Alperovich

คุณช่วยชี้แจงได้ไหมว่าอินสแตนซ์ที่สร้างขึ้นที่นี่เป็นซิงเกิลตันของบริการ "จริง" หรือเป็นเพียงอินสแตนซ์ของบริการที่ถูกยกเลิกเมื่อ Angular ใช้เวทมนตร์ของหัวฉีดจริง
Eric

เอริคฉันไม่สามารถยืนยันได้ในตอนนี้ อย่างไรก็ตามสิ่งที่ฉันมักจะทำ (ถ้ามี) คือangular.injector(['mymodule'])- แต่ฉันไม่แน่ใจว่าคุณสามารถใช้แนวทางนี้สำหรับ$httpบริการได้หรือไม่ ฉันอยากจะบอกว่าฉันมี ไม่แน่ใจว่าช่วยได้หรือไม่: - /
Cody

2
นี่ควรเป็นคำตอบที่ได้รับการยอมรับ ฉันพยายามอย่างเต็มที่ในขณะที่พยายามทำให้สิ่งนี้ได้ผลและวิธีนี้ช่วยแก้ปัญหาของฉันได้ทันที ฉันคิดว่านี่อาจเป็นปัญหาที่พบบ่อยมาก ขอบคุณ @Cody
iamdash

5
ฉันยืนยันว่าโซลูชันที่ยอมรับใช้ไม่ได้กับการใช้ $ http ในผู้ให้บริการ แต่คำตอบของ @Cody ทำให้เคล็ดลับ
Dino

1

นี่เป็นคำถามเก่าดูเหมือนว่าเราจะมีไข่ไก่เกิดขึ้นหากเราต้องการพึ่งพาความสามารถหลักของห้องสมุด

แทนที่จะแก้ปัญหาด้วยวิธีการพื้นฐานสิ่งที่ฉันทำคือการผ่าน สร้างคำสั่งที่ห่อหุ้มร่างกายทั้งหมด เช่น

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

สำหรับฉันแล้วดูเหมือนว่าฉันสามารถควบคุมลำดับของ bootstrap ได้หลังจากที่ bootstrap ปกติแก้ไขการกำหนดค่าผู้ให้บริการทั้งหมดแล้วลองเริ่มต้นmc-bodyคำสั่ง

และดูเหมือนว่าคำสั่งนี้สำหรับฉันสามารถนำหน้าการกำหนดเส้นทางได้เนื่องจากการกำหนดเส้นทางจะถูกแทรกผ่านคำสั่งเช่นกัน <ui-route />. แต่ฉันคิดผิดในเรื่องนี้ ต้องการการตรวจสอบเพิ่มเติม


คุณช่วยอธิบายวิธีแก้ปัญหาของคุณอย่างละเอียดได้ไหม
มาร์ค

-2

ในการตอบคำถามของคุณ "มีไอเดียไหม" ฉันจะตอบว่า "ใช่" แต่เดี๋ยวก่อนยังมีอีก!

ฉันขอแนะนำให้ใช้ 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);
        }
    });
}]);

$ customProvider ในการเรียกกลับสำเร็จรวมถึง $ ราวกับว่าเป็นผู้ให้บริการภายใน
Jeff Fischer

1
คุณคิดถูกแล้วที่ฉันมีส่วนผสมของ $ และไม่ใช่ $ ฉันอัปเดตเป็น $ ทั้งหมด
Suamere
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.