Які "речі" можна вводити іншим у Angular.js?


142

Мені трохи важко зрозуміти введення залежності в кутовий. Отже, моє запитання полягає в тому, чи може хтось пояснити, який із "типів", таких як контролер, фабрика, постачальник тощо, ми можемо ввести іншим особам, включаючи інші екземпляри такого ж типу?

Що я насправді шукаю - це таблиця, заповнена y / n. Для комірок з тим самим рядком / стовпцем це означає введення значення одного "типу" в інший інший з тим же "типом"

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

Відповіді:


391

Замість того, щоб просто заповнити таблицю словами "так" і "ні" без жодних пояснень, я піду трохи детальніше.

[Зауважте, додано після закінчення: це в кінцевому підсумку було ... трохи довше, ніж я очікував. Внизу є tl; dr, але я сподіваюся, що це буде інформаційно.]

[Ця відповідь також була додана у вікі AngularJS: Розуміння ін'єкції залежності ]


Постачальник ( $provide)

$provideСлужба відповідає за розповідь ANGULAR , як створювати нові ін'єкційні речі; ці речі називаються послугами . Служби визначаються речами, які називаються постачальниками. Це те, що ви створюєте під час використання $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функції (він же - наша 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методи провайдерів (інакше factoryфункція визначення)

Оскільки constants і values завжди повертають статичне значення, вони не викликаються через інжектор, і тому ви нічого не можете вводити їм.

Налаштування постачальників

Ви можете бути здивовані , чому хтось -то буде турбувати , щоб створити повноцінний провайдер з provideметодом , якщо factory, valueі т.д. так набагато простіше. Відповідь полягає в тому, що провайдери дозволяють багато конфігурації. Ми вже згадували, що коли ви створюєте послугу через постачальника (або будь-який із ярликів, який надає Angular), ви створюєте нового постачальника, який визначає, як будується ця послуга. Що я не згадував, це те, що ці постачальники можуть вводитись у configрозділи вашої програми, щоб ви могли з ними взаємодіяти!

По-перше, Angular запускає вашу програму у дві фази - 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це ярлики для налаштування цих служб.


тл; д-р

Отже, підводячи підсумок, будь-яка функція, яку $injector.invoke можна викликати, може бути введена в неї . Сюди входить ваша діаграма (але не обмежується ними):

  • контролер
  • директива
  • фабрика
  • фільтр
  • постачальник $get(при визначенні постачальника як об’єкта)
  • функція провайдера (при визначенні провайдера як функції конструктора)
  • сервіс

Провайдер створює нові послуги, які можна вводити в речі . Це включає:

  • постійний
  • фабрика
  • постачальник
  • сервіс
  • значення

Однак, вбудовані сервіси на кшталт $controllerі $filter можуть бути введені ін'єкцією, і ви можете скористатися цією службою, щоб отримати нові фільтри та контролери, які ви визначили за допомогою цих методів (навіть якщо те, що ви визначили, самі по собі не можуть бути вводиться в речі).

Окрім цього, будь-яку функцію, що викликається інжектором, можна вводити будь-яку послугу, що надається постачальником - немає ніяких обмежень (крім перелічених тут configі runвідмінностей).


6
Оце Так! дякую, що знайшли час, щоб відповісти так детально! Я читав це двічі, і, думаю, я зрозумів зовсім небагато. Ознайомтесь із цим посиланням та посиланнями, які ви детально розповіли пізніше сьогодні. І ще +1 для кота. :)
користувач1527166

18
Один з найкорисніших і детальних відповідей на відповідь, на які я потрапив - дякую!
Годдерс

11
Ця відповідь визначає новий рівень приголомшливого. Освітлюючі речі.
Ngure Nyaga

4
На сьогоднішній день найкращий ресурс, з яким я стикався для AngularJS. Дякую.
код90

5
Буквально найкращий фрагмент документації AngularJS, яку я бачив. Шлях!
Ієн Дункан

13

Справа в тому, що BinaryMuse робить свою дивовижну відповідь про постачальників, фабрики та послуги, які є одне і те ж саме надзвичайно важливим.

Нижче наведено зображення, яке, на мою думку, може наочно проілюструвати її суть:

AngularJS - всі вони просто постачальники
(джерело: простоgoodcode.com )


7

Чудова відповідь Мішель. Я просто хочу зазначити, що директиви можна вводити. Якщо у вас є ім'я директиви myThing, ви можете ввести її за допомогою myThingDirective: Ось надуманий приклад .

Наведений вище приклад не дуже практичний, однак можливість введення директиви корисна, коли ви хочете прикрасити цю директиву .


Здається, що другий приклад прикраси цієї директиви не працює з Angular 1.4. (дивіться коментар Хуана Біскайя там)
Vadorequest
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.