“ สิ่งต่าง ๆ ” ใดบ้างที่สามารถแทรกเข้าไปในสิ่งอื่นใน Angular.js


142

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

สิ่งที่ฉันกำลังมองหาคือตารางนี้เต็มไปด้วย y / n สำหรับเซลล์ที่มีแถว / คอลัมน์เดียวกันนั่นหมายถึงการฉีดค่า "ชนิด" หนึ่งลงในอีกเซลล์หนึ่งที่มี "ประเภท" เดียวกัน

+----------------+----------+------------+-----------+---------+--------+----------+---------+-------+
| Can we inject? | Constant | Controller | Directive | Factory | Filter | Provider | Service | Value |
+----------------+----------+------------+-----------+---------+--------+----------+---------+-------+
| Constant       |          |            |           |         |        |          |         |       |
| Controller     |          |            |           |         |        |          |         |       |
| Directive      |          |            |           |         |        |          |         |       |
| Factory        |          |            |           |         |        |          |         |       |
| Filter         |          |            |           |         |        |          |         |       |
| Provider       |          |            |           |         |        |          |         |       |
| Service        |          |            |           |         |        |          |         |       |
| Value          |          |            |           |         |        |          |         |       |
+----------------+----------+------------+-----------+---------+--------+----------+---------+-------+

นี่คือการตอบสนองdocs.angularjs.org/guide/providers #conclusion
JFouad

คำตอบ:


391

แทนที่จะกรอกตารางด้วย "ใช่" และ "ไม่" โดยไม่มีคำอธิบายฉันจะพูดถึงรายละเอียดเพิ่มเติมเล็กน้อย

[หมายเหตุเพิ่มหลังจากเสร็จสิ้น: สิ่งนี้จบลงแล้ว ... นานกว่าที่ฉันคาดไว้สักหน่อย มี tl; dr ที่ด้านล่าง แต่ฉันหวังว่านี่จะเป็นข้อมูลให้]

[คำตอบนี้ถูกเพิ่มไปยังวิกิ AngularJS: การทำความเข้าใจการพึ่งพาการฉีด ]


ผู้ให้บริการ ( $provide)

$provideบริการเป็นผู้รับผิดชอบบอกเชิงมุมวิธีการสร้างสิ่งฉีดใหม่ สิ่งเหล่านี้จะเรียกว่าบริการ บริการจะถูกกำหนดโดยสิ่งที่เรียกว่าผู้ให้บริการ$provideซึ่งเป็นสิ่งที่คุณกำลังสร้างเมื่อคุณใช้ การกำหนดผู้ให้บริการจะทำผ่านproviderวิธีการในการ$provideบริการและคุณสามารถรับ$provideบริการโดยขอให้มันถูกฉีดเข้าไปในconfigฟังก์ชั่นการใช้งานของ ตัวอย่างอาจเป็นดังนี้:

app.config(function($provide) {
  $provide.provider('greeting', function() {
    this.$get = function() {
      return function(name) {
        alert("Hello, " + name);
      };
    };
  });
});

ที่นี่เราได้กำหนดไว้ให้บริการใหม่สำหรับบริการที่เรียกว่าgreeting; เราสามารถฉีดตัวแปรที่มีชื่อgreetingลงในฟังก์ชั่นการฉีดใด ๆ (เช่นตัวควบคุมเพิ่มเติมในภายหลัง) และ Angular จะเรียกใช้$getฟังก์ชันของผู้ให้บริการเพื่อส่งคืนอินสแตนซ์ใหม่ของบริการ ในกรณีนี้สิ่งที่จะถูกฉีดคือฟังก์ชันที่รับnameพารามิเตอร์และalertข้อความ sa ตามชื่อ เราอาจใช้สิ่งนี้:

app.controller('MainController', function($scope, greeting) {
  $scope.onClick = function() {
    greeting('Ford Prefect');
  };
});

นี่คือเคล็ดลับ factory, serviceและvalueเป็นเพียงทางลัดเพื่อกำหนดส่วนต่าง ๆ ของผู้ให้บริการ - นั่นคือพวกเขามีวิธีการกำหนดผู้ให้บริการโดยไม่ต้องพิมพ์สิ่งที่ออกทั้งหมด ตัวอย่างเช่นคุณสามารถเขียนผู้ให้บริการรายเดียวกันนั้นได้เช่นนี้

app.config(function($provide) {
  $provide.factory('greeting', function() {
    return function(name) {
      alert("Hello, " + name);
    };
  });
});

สิ่งสำคัญคือต้องเข้าใจดังนั้นฉันจะใช้ถ้อยคำใหม่: ภายใต้ประทุน AngularJS กำลังเรียกใช้รหัสเดียวกันกับที่เราเขียนไว้ด้านบน ( $provide.providerฉบับ) สำหรับเรา แท้จริงแล้วไม่มีความแตกต่างในสองเวอร์ชั่นนี้ 100% valueทำงานเพียงวิธีเดียว - ถ้าสิ่งที่เราจะกลับมาจากการที่เรา$getฟังก์ชั่น (aka ของเราfactoryฟังก์ชั่น) valueอยู่เสมอเหมือนกันเราสามารถเขียนโค้ดแม้แต่น้อยโดยใช้ ตัวอย่างเช่นเนื่องจากเราส่งคืนฟังก์ชันเดียวกันสำหรับgreetingบริการของเราเราจึงสามารถใช้valueเพื่อกำหนดได้เช่นกัน:

app.config(function($provide) {
  $provide.value('greeting', function(name) {
    alert("Hello, " + name);
  });
});

อีกครั้งนี่เป็น 100% เหมือนกันกับอีกสองวิธีที่เราเคยใช้เพื่อกำหนดฟังก์ชั่นนี้ - มันเป็นวิธีหนึ่งในการบันทึกการพิมพ์

ตอนนี้คุณอาจสังเกตเห็นapp.config(function($provide) { ... })สิ่งที่น่ารำคาญที่ฉันใช้อยู่ เนื่องจากการกำหนดผู้ให้บริการใหม่ (ผ่านวิธีการใด ๆที่ระบุด้านบน) เป็นเรื่องธรรมดา AngularJS จะเปิดเผย$providerวิธีการโดยตรงบนวัตถุโมดูลเพื่อประหยัดการพิมพ์มากยิ่งขึ้น:

var myMod = angular.module('myModule', []);

myMod.provider("greeting", ...);
myMod.factory("greeting", ...);
myMod.value("greeting", ...);

สิ่งเหล่านี้ทำในสิ่งเดียวกันกับapp.config(...)เวอร์ชั่นที่เราใช้มาก่อนหน้านี้

constantที่ผมเคยฉีดหนึ่งข้ามเพื่อให้ห่างไกล valueสำหรับตอนนี้ก็พอง่ายที่จะพูดว่ามันทำงานเช่นเดียวกับ เราจะเห็นว่ามีข้อแตกต่างในภายหลัง

ในการตรวจสอบ , ทุกชิ้นส่วนเหล่านี้ของรหัสที่กำลังทำที่แน่นอนสิ่งเดียวกัน

myMod.provider('greeting', function() {
  this.$get = function() {
    return function(name) {
      alert("Hello, " + name);
    };
  };
});

myMod.factory('greeting', function() {
  return function(name) {
    alert("Hello, " + name);
  };
});

myMod.value('greeting', function(name) {
  alert("Hello, " + name);
});

หัวฉีด ( $injector)

หัวฉีดเป็นผู้รับผิดชอบจริงการสร้างอินสแตนซ์ของการบริการของเราโดยใช้โค้ดที่เราให้ผ่าน$provide(ไม่มีเล่นสำนวนเจตนา) เมื่อใดก็ตามที่คุณเขียนฟังก์ชั่นที่รับการโต้เถียงคุณจะเห็นหัวฉีดในที่ทำงาน แต่ละแอปพลิเคชัน AngularJS มีซิงเกิ้ล$injectorที่สร้างขึ้นเมื่อแอปพลิเคชันเริ่มต้นครั้งแรก คุณสามารถจับมันได้โดยการฉีด$injectorเข้าไปในฟังก์ชั่นการฉีด (ใช่$injectorรู้วิธีฉีดเอง!)

เมื่อคุณมี$injectorแล้วคุณจะได้รับอินสแตนซ์ของบริการที่กำหนดโดยเรียกใช้บริการgetพร้อมชื่อบริการ ตัวอย่างเช่น,

var greeting = $injector.get('greeting');
greeting('Ford Prefect');

หัวฉีดยังรับผิดชอบในการฉีดบริการลงในฟังก์ชั่น; ตัวอย่างเช่นคุณสามารถฉีดบริการลงในฟังก์ชันใด ๆ ที่คุณใช้invokeวิธีการของหัวฉีดได้อย่างน่าอัศจรรย์

var myFunction = function(greeting) {
  greeting('Ford Prefect');
};
$injector.invoke(myFunction);

คุ้มค่าสังเกตว่าหัวฉีดเท่านั้นที่จะสร้างตัวอย่างของบริการที่ใช้งานครั้งเดียว จากนั้นจะแคชสิ่งใดก็ตามที่ผู้ให้บริการส่งคืนโดยใช้ชื่อของบริการ ครั้งต่อไปที่คุณขอใช้บริการคุณจะได้รับวัตถุเดียวกันแน่นอน

ดังนั้นเพื่อตอบคำถามของคุณคุณสามารถฉีดบริการเข้าสู่ฟังก์ชั่นใด ๆ $injector.invokeที่เรียกว่ามี ซึ่งรวมถึง

  • ฟังก์ชันนิยามคอนโทรลเลอร์
  • ฟังก์ชันการกำหนดคำสั่ง
  • ฟังก์ชันนิยามตัวกรอง
  • $getวิธีการของผู้ให้บริการ (aka factoryฟังก์ชั่นความหมาย)

เนื่องจากconstants และvalues ส่งคืนค่าสแตติกเสมอพวกมันจะไม่ถูกเรียกผ่านหัวฉีดดังนั้นคุณจึงไม่สามารถฉีดด้วยสิ่งใดก็ได้

การกำหนดค่าผู้ให้บริการ

คุณอาจจะสงสัยว่าทำไมทุกคนจะรำคาญที่จะตั้งขึ้นเป็นผู้ให้บริการที่เต็มเปี่ยมด้วยprovideวิธีถ้าfactory, valueฯลฯ มากขึ้น คำตอบคือผู้ให้บริการอนุญาตการกำหนดค่าจำนวนมาก เราได้กล่าวแล้วว่าเมื่อคุณสร้างบริการผ่านผู้ให้บริการ (หรือทางลัดใด ๆ ที่ Angular มอบให้คุณ) คุณจะสร้างผู้ให้บริการใหม่ที่กำหนดวิธีการสร้างบริการนั้น สิ่งที่ฉันไม่ได้กล่าวถึงคือผู้ให้บริการเหล่านี้สามารถแทรกลงในconfigส่วนของแอปพลิเคชันของคุณเพื่อให้คุณสามารถโต้ตอบกับพวกเขาได้!

อันดับแรกแองกูลาร์รันแอปพลิเคชันของคุณในสองเฟส - configและrunเฟส configขั้นตอนที่เราได้เห็นเป็นที่ที่คุณสามารถตั้งค่าให้บริการใด ๆ ตามความจำเป็น นี่คือจุดที่คำสั่งตัวควบคุมตัวกรองและสิ่งที่คล้ายกัน runเฟสที่คุณอาจจะคิดว่าเป็นที่ที่เชิงมุมจริงรวบรวม DOM ของคุณและเริ่มต้นขึ้นของแอป

คุณสามารถเพิ่มรหัสเพิ่มเติมที่จะทำงานในขั้นตอนเหล่านี้ด้วยmyMod.configและmyMod.runฟังก์ชั่น - แต่ละฟังก์ชั่นที่จะทำงานในช่วงที่เฉพาะเจาะจง ดังที่เราเห็นในส่วนแรกฟังก์ชั่นเหล่านี้สามารถฉีดได้ - เราฉีด$provideบริการที่มีอยู่แล้วในตัวอย่างโค้ดแรกของเรา อย่างไรก็ตามสิ่งที่น่าสังเกตคือในconfigช่วงนี้มีเพียงผู้ให้บริการเท่านั้นที่สามารถทำการฉีด (ยกเว้นบริการในAUTOโมดูล - $provideและ$injector)

ตัวอย่างเช่นสิ่งต่อไปนี้ไม่ได้รับอนุญาต :

myMod.config(function(greeting) {
  // WON'T WORK -- greeting is an *instance* of a service.
  // Only providers for services can be injected in config blocks.
});

สิ่งที่คุณทำมีการเข้าถึงผู้ใดเป็นผู้ให้บริการสำหรับการให้บริการที่คุณได้ทำ:

myMod.config(function(greetingProvider) {
  // a-ok!
});

มีข้อยกเว้นที่สำคัญข้อหนึ่ง: constants เนื่องจากพวกเขาไม่สามารถเปลี่ยนแปลงได้จึงได้รับอนุญาตให้ฉีดเข้าไปภายในconfigบล็อก (นี่คือความแตกต่างจากvalues) พวกเขาเข้าถึงได้โดยใช้ชื่อของตนเองเพียงอย่างเดียว (ไม่Providerจำเป็นต้องใส่คำต่อท้าย)

เมื่อใดก็ตามที่คุณกำหนดผู้ให้บริการสำหรับบริการผู้ให้บริการนั้นจะได้รับการตั้งชื่อserviceProviderโดยserviceเป็นชื่อของบริการ ตอนนี้เราสามารถใช้พลังของผู้ให้บริการทำสิ่งที่ซับซ้อนมากขึ้น!

myMod.provider('greeting', function() {
  var text = 'Hello, ';

  this.setText = function(value) {
    text = value;
  };

  this.$get = function() {
    return function(name) {
      alert(text + name);
    };
  };
});

myMod.config(function(greetingProvider) {
  greetingProvider.setText("Howdy there, ");
});

myMod.run(function(greeting) {
  greeting('Ford Prefect');
});

ตอนนี้เรามีฟังก์ชั่นกับผู้ให้บริการของเราที่เรียกsetTextว่าเราสามารถใช้ในการปรับแต่งของเราalert ; เราสามารถเข้าถึงผู้ให้บริการรายนี้ในconfigบล็อกเพื่อเรียกใช้วิธีนี้และปรับแต่งบริการ เมื่อเรารันแอพของเราในที่สุดเราสามารถคว้าgreetingบริการและลองใช้งานเพื่อดูว่าการปรับแต่งของเรามีผล

เนื่องจากนี่เป็นตัวอย่างที่ซับซ้อนมากขึ้นต่อไปนี้เป็นการสาธิตการทำงาน: http://jsfiddle.net/BinaryMuse/9GjYg/

ตัวควบคุม ($controller )

สามารถฉีดฟังก์ชั่นของคอนโทรลเลอร์ได้ แต่ตัวควบคุมจะไม่สามารถฉีดเข้าไปในสิ่งอื่นได้ นั่นเป็นเพราะตัวควบคุมไม่ได้ถูกสร้างผ่านผู้ให้บริการ แต่มีบริการ Angular ในตัว$controllerที่เรียกว่ารับผิดชอบการตั้งค่าตัวควบคุมของคุณ เมื่อคุณโทรmyMod.controller(...)คุณกำลังเข้าถึงผู้ให้บริการนี้จริง ๆเหมือนกับในส่วนสุดท้าย

ตัวอย่างเช่นเมื่อคุณกำหนดคอนโทรลเลอร์เช่นนี้:

myMod.controller('MainController', function($scope) {
  // ...
});

สิ่งที่คุณทำจริงๆคือ:

myMod.config(function($controllerProvider) {
  $controllerProvider.register('MainController', function($scope) {
    // ...
  });
});

ต่อมาเมื่อ Angular ต้องการสร้างอินสแตนซ์ของคอนโทรลเลอร์ของคุณมันจะใช้$controllerบริการ (ซึ่งจะใช้ใน$injectorการเรียกใช้ฟังก์ชั่นคอนโทรลเลอร์ของคุณ

ตัวกรองและคำสั่ง

filterและdirectiveทำงานในลักษณะเดียวกับcontroller; filterใช้บริการที่เรียกว่า$filterและผู้ให้บริการ$filterProviderในขณะที่directiveการใช้บริการที่เรียกว่าและผู้ให้บริการของตน$compile $compileProviderลิงค์บางส่วน:

ตามตัวอย่างอื่น ๆmyMod.filterและmyMod.directiveเป็นทางลัดในการกำหนดค่าบริการเหล่านี้


TL; DR

ดังนั้นเพื่อสรุปการทำงานใด ๆ ที่ได้รับการเรียกว่ามีสามารถฉีดเข้าไป$injector.invoke ซึ่งรวมถึงจากแผนภูมิของคุณ (แต่ไม่ จำกัด เฉพาะ):

  • ตัวควบคุม
  • คำสั่ง
  • โรงงาน
  • กรอง
  • ผู้ให้บริการ$get(เมื่อกำหนดผู้ให้บริการเป็นวัตถุ)
  • ฟังก์ชั่นผู้ให้บริการ (เมื่อกำหนดผู้ให้บริการเป็นฟังก์ชั่นคอนสตรัค)
  • บริการ

ผู้ให้บริการสร้างบริการใหม่ที่สามารถฉีดเข้าไปในสิ่งต่างๆ รวมถึง:

  • คงที่
  • โรงงาน
  • ผู้ให้บริการ
  • บริการ
  • ความคุ้มค่า

ที่กล่าวว่าบริการในตัวเช่น$controllerและ$filter สามารถฉีดและคุณสามารถใช้บริการเหล่านั้นเพื่อระงับตัวกรองและตัวควบคุมใหม่ที่คุณกำหนดด้วยวิธีการเหล่านั้น (แม้ว่าสิ่งที่คุณกำหนดจะไม่สามารถทำได้ด้วยตนเอง ฉีดเข้าไปในสิ่งต่าง ๆ )

นอกเหนือจากนั้นฟังก์ชั่นใด ๆ ที่เรียกใช้หัวฉีดสามารถถูกฉีดเข้ากับบริการที่ผู้ให้บริการกำหนดไว้ - ไม่มีข้อ จำกัด (นอกเหนือจากconfigและrunความแตกต่างที่ระบุไว้ในที่นี้)


6
ว้าว! ขอบคุณที่สละเวลาตอบรายละเอียดดังกล่าว! ฉันอ่านมันสองครั้งและฉันคิดว่าฉันเข้าใจค่อนข้างน้อย จะศึกษามันและลิงค์ที่คุณให้รายละเอียดในวันนี้ และอีก +1 สำหรับแมว :)
user1527166

18
หนึ่งในคำตอบที่มีประโยชน์และมีรายละเอียดมากที่สุดที่ฉันได้เจอ - ขอบคุณ!
Godders

11
คำตอบนี้กำหนดระดับใหม่ที่น่ากลัว สิ่งที่ให้แสงสว่าง
Ngure Nyaga

4
โดยทรัพยากรที่ดีที่สุดที่ฉันได้เจอสำหรับ AngularJS ขอบคุณ
code90

5
แท้จริงแล้ว AngularJS เป็นเอกสารชิ้นที่ดีที่สุดที่ฉันเคยเห็น ทางที่จะไป!
เลนดันแคน

13

จุดที่ BinaryMuse ให้คำตอบที่น่าทึ่งเกี่ยวกับผู้ให้บริการโรงงานและบริการล้วนเป็นสิ่งเดียวกันที่สำคัญอย่างยิ่ง

ด้านล่างเป็นภาพที่ฉันคิดว่าสามารถอธิบายจุดของเธอได้:

AngularJS เป็นเพียงผู้ให้บริการเท่านั้น
(ที่มา: simplygoodcode.com )


7

คำตอบที่ยอดเยี่ยมโดยมิเชล ฉันแค่ต้องการชี้ให้เห็นว่าคำสั่งสามารถฉีด หากคุณมีคำสั่งชื่อmyThingคุณสามารถฉีดด้วยmyThingDirective: นี่เป็นตัวอย่างที่วางแผนไว้นี่เป็นตัวอย่างที่วางแผนไว้

ตัวอย่างข้างต้นไม่สามารถใช้งานได้จริง แต่ความสามารถในการฉีดคำสั่งจะมีประโยชน์เมื่อคุณต้องการตกแต่งคำสั่งนั้น


ดูเหมือนว่าตัวอย่างที่สองในการตกแต่งคำสั่งนั้นไม่ทำงานตั้งแต่ Angular 1.4 (ดูความคิดเห็นของJuan Biscaia ที่นั่น)
Vadorequest
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.