Angular.js'de başkalarına hangi “şeyler” enjekte edilebilir?


142

Angular'da Bağımlılık Enjeksiyonunu anlamakta biraz zorlanıyorum. Öyleyse sorum şu, Kontrolör, Fabrika, Sağlayıcı, vb. Gibi "türlerden" hangisinin aynı "tür" diğer örnekleri de dahil olmak üzere başkalarına enjekte edebilir miyiz?

Aslında aradığım bu tablo y / n ile dolu. Aynı satır / sütuna sahip hücreler için bu, bir "tür" değerinin diğerine aynı "tür" değerine enjekte edilmesi anlamına gelir

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

Yanıtlar:


391

Bunun yerine, tabloyu "evet" ve "hayır" ile hiçbir açıklama yapmadan doldurmak yerine, biraz daha ayrıntıya gireceğim.

[Not, bitirdikten sonra eklendi: Bu sona erdi ... beklediğimden biraz daha uzun. Altta bir tl var; ama umarım bu bilgilendirici olur.]

[Bu cevap AngularJS wiki'ye eklenmiştir: Bağımlılık Enjeksiyonunu Anlamak ]


Sağlayıcı ( $provide)

$provideHizmet nasıl yeni enjektabl şeyler oluşturmak için açısal anlatan sorumludur; bunlara hizmet denir . Hizmetler, sağlayıcılar olarak adlandırılan şeylerle tanımlanır ; bu, kullandığınızda oluşturduğunuz şeydir $provide. Bir sağlayıcı tanımlamak provider, $providehizmet üzerindeki yöntemle yapılır ve $providebir uygulamanın configişlevine enjekte edilmesini isteyerek hizmeti alabilirsiniz . Bir örnek şöyle olabilir:

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

Burada greeting; adlı bir hizmet için yeni bir sağlayıcı tanımladık ; greetingherhangi bir enjekte edilebilir işleve ( değişkenler gibi daha sonraları) adlandırılan bir değişkeni enjekte edebiliriz ve Angular $get, hizmetin yeni bir örneğini döndürmek için sağlayıcının işlevini çağıracaktır . Bu durumda, enjekte edilecek şey , isme dayalı bir nameparametre ve alertsa mesajı alan bir işlevdir . Bunu şu şekilde kullanabiliriz:

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

Şimdi işte püf noktası. factory,, serviceve valuehepsi bir sağlayıcının çeşitli bölümlerini tanımlamak için kısayollardır - yani, tüm bu şeyleri yazmak zorunda kalmadan bir sağlayıcı tanımlamak için bir araç sağlarlar. Örneğin, aynı sağlayıcıyı şu şekilde yazabilirsiniz :

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

Ben başka bir şekilde ifade edeceğiz, bu yüzden anlamak önemlidir: başlık altında, angularjs çağırıyor kodun aynısını biz (yukarıda yazdığı $provide.providersürümü) için bize. Kelimenin tam anlamıyla, iki versiyonda% 100 fark yoktur. valueaynı şekilde çalışır - $getfonksiyonumuzdan ne dönersek (aka factoryfonksiyonumuz) her zaman aynı ise, kullanarak daha az kod yazabiliriz value. Örneğin, greetinghizmetimiz için her zaman aynı işlevi döndürdüğümüz için , bunu valuetanımlamak için de kullanabiliriz :

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

Yine, bu, bu işlevi tanımlamak için kullandığımız diğer iki yöntemle% 100 özdeştir - bu, biraz yazmayı kaydetmenin bir yoludur.

Muhtemelen kullandığım bu sinir bozucu app.config(function($provide) { ... })şeyi fark ettiniz . Yeni sağlayıcılar tanımlamak ( yukarıda verilen yöntemlerden herhangi biri aracılığıyla ) çok yaygın olduğundan, AngularJS $provideryöntemleri daha da fazla yazmak için yöntemleri doğrudan modül nesnesine maruz bırakır :

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

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

Bunların hepsi, daha app.config(...)önce kullandığımız daha ayrıntılı sürümlerle aynı şeyi yapıyor .

Şimdiye kadar atladığım enjektabl constant. Şimdilik, aynı şekilde çalıştığını söylemek yeterince kolay value. Sonradan bir fark göreceğiz.

İnceleme için , tüm bu kod parçaları yapıyoruz tam aynı şeyi:

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

Enjektör ( $injector)

Enjektör, sağladığımız kodu kullanarak hizmetlerimizin örneklerini oluşturmaktan sorumludur $provide(cezalandırma amaçlı değildir). Enjekte edilen argümanları alan bir işlev yazdığınızda, enjektörü iş başında görürsünüz. Her AngularJS uygulamasında, $injectoruygulama ilk başlatıldığında oluşturulan bir tane vardır; $injectorEnjekte edilebilir herhangi bir işleve enjekte ederek onu tutabilirsiniz (evet, $injectorkendini nasıl enjekte edeceğini bilir!)

Elinize geçtikten sonra , hizmetin adıyla $injectorarayarak tanımlı bir hizmetin örneğini alabilirsiniz get. Örneğin,

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

Enjektör ayrıca hizmetlerin işlevlere enjekte edilmesinden de sorumludur; örneğin, enjektör invokeyöntemini kullanarak hizmetleri herhangi bir işleve sihirli bir şekilde enjekte edebilirsiniz ;

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

Enjektörün sadece bir kez bir servis örneği oluşturacağını belirtmek gerekir . Daha sonra, sağlayıcının hizmet adıyla döndürdüğü her şeyi önbelleğe alır; bir dahaki sefere hizmeti istediğinizde, tam olarak aynı nesneyi alırsınız.

Böylece, sorunuzu cevaplamak için , çağrılan herhangi bir işleve$injector.invoke hizmetler enjekte edebilirsiniz . Bu içerir

  • denetleyici tanımı fonksiyonları
  • yönerge tanımlama fonksiyonları
  • filtre tanımlama fonksiyonları
  • $get(aka sağlayıcılarının yöntemleri factorytanımı fonksiyonları)

Yana constantler ve valueher zaman statik bir değer döndürmek s, onlar enjektör vasıtasıyla çağrılan, olup, dolayısı onlarla iğne şeyle yapamazsınız.

Sağlayıcıları Yapılandırma

Herkes ile tam teşekküllü sağlayıcı kurmak neden rahatsız ediyor olabilirsiniz provideyöntemle eğer factory, valueçok daha kolaydır, vb. Cevap, sağlayıcıların çok fazla yapılandırmaya izin vermesidir. Sağlayıcı aracılığıyla bir hizmet oluşturduğunuzda (veya Angular'ın size sağladığı kısayollardan herhangi birinde), bu hizmetin nasıl oluşturulduğunu tanımlayan yeni bir sağlayıcı oluşturduğunuzdan daha önce bahsetmiştik. Ne vermedi söz bu sağlayıcılar enjekte edilebilir olmasıdır configonlarla etkileşim kurabilmek için uygulamanızın bölümlerinde!

İlk olarak, Açısal uygulamanızı iki aşamada ( configve runaşamaları) çalıştırır. configGerekli gibi herhangi sağlayıcıları ayarlayabilirsiniz nereye faz, gördüğümüz gibi olduğunu. Burası aynı zamanda direktiflerin, kontrolörlerin, filtrelerin ve benzerlerinin ayarlandığı yerdir. runTahmin edeceğiniz gibi Eğik aslında DOM derler ve uygulamanızı başladığı aşama vardır.

Ek kod ile bu aşamada çalıştırılacak ekleyebilir myMod.configve myMod.runfonksiyonları - Her bu özel aşamasında çalıştırmak için bir işlev alır. İlk bölümde gördüğümüz gibi, bu fonksiyonlar enjekte edilebilir - $provideilk kod örneğimize dahili servisi enjekte ettik. Bununla birlikte, dikkat edilmesi gereken şey, aşama sırasında configsadece sağlayıcıların enjekte edilebilmesidir ( AUTOmodüldeki hizmetler hariç - $provideve $injector).

Örneğin, aşağıdakilere izin verilmez :

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

Ne yapmak herhangi vardır erişimi sağlayıcılar Yaptığınız hizmetler için:

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

Önemli bir istisna vardır: constantdeğiştirilemedikleri için configblokların içine enjekte edilmelerine izin verilir ( values'den farklı olmaları budur ). Bunlara yalnızca isimleriyle erişilir ( Providersonek gerekmez).

Eğer bir hizmet için bir sağlayıcı tanımlanmış zaman, o sağlayıcı olarak adlandırılmış serviceProvidernerede, servicehizmetin adıdır. Şimdi sağlayıcıların gücünü daha karmaşık şeyler yapmak için kullanabiliriz!

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

Şimdi hizmet sağlayıcımızda setText, özelleştirmek için kullanabileceğimiz bir fonksiyonumuz var alert; configbu yöntemi çağırmak ve hizmeti özelleştirmek için bu sağlayıcıya bir blokta erişebiliriz . Sonunda bizim app çalıştırmak, biz greetinghizmet kapmak ve bizim özelleştirme etkili olduğunu görmek için deneyebilirsiniz.

Bu daha karmaşık bir örnek olduğundan, işleyen bir gösteri: http://jsfiddle.net/BinaryMuse/9GjYg/

Denetleyiciler ( $controller)

Denetleyici işlevleri enjekte edilebilir, ancak denetleyicilerin kendileri başka şeylere enjekte edilemez. Bunun nedeni denetleyicilerin sağlayıcı aracılığıyla oluşturulmamasıdır. Bunun yerine, $controllerdenetleyicilerinizi kurmaktan sorumlu yerleşik bir Açısal hizmet vardır . Aradığınızda myMod.controller(...), aslında erişiyorsanız bu hizmetin sağlayıcısı sadece son bölümde olduğu gibi.

Örneğin, böyle bir denetleyici tanımladığınızda:

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

Aslında yaptığınız şey:

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

Daha sonra, Angular'ın denetleyicinizin bir örneğini oluşturması gerektiğinde, $controllerhizmeti kullanır (bu da $injectordenetleyicinizin işlevini çağırmak için kullanır, böylece bağımlılıkları da enjekte edilir).

Filtreler ve Yönergeler

filterve directivetam olarak aynı şekilde çalışır controller; filterBir denir hizmeti kullanan $filterve sağlayıcı $filterProvideriken directivebir hizmet olarak adlandırılan kullanımları $compileve sağlayıcı $compileProvider. Bazı bağlantılar:

Diğer örneklere göre myMod.filterve myMod.directivebu hizmetleri yapılandırmak için kısayollardır.


tl; Dr.

Özetlemek gerekirse, çağrılan herhangi bir fonksiyon $injector.invoke enjekte edilebilir . Bu, grafiğinizden (ancak bunlarla sınırlı değildir) şunları içerir:

  • kontrolör
  • direktif
  • fabrika
  • filtre
  • sağlayıcı $get(sağlayıcıyı nesne olarak tanımlarken)
  • sağlayıcı işlevi (sağlayıcıyı yapıcı işlevi olarak tanımlarken)
  • hizmet

Sağlayıcı, şeylere enjekte edilebilen yeni hizmetler oluşturur . Bu içerir:

  • sabit
  • fabrika
  • Sağlayıcı
  • hizmet
  • değer

Yani gibi hizmetler dahili dedi $controllerve $filter olabilir enjekte edilecek ve yapabilecekleriniz kullanmak , kendileri tarafından bu yöntemlerden (tanımladığınız şeyler değildir halde tanımlanmış yeni filtreleri ve denetleyicileri ele almak için bu hizmeti, muktedir şeylere enjekte edilir).

Bunun dışında, enjektör tarafından başlatılan herhangi bir işlev sağlayıcı tarafından sağlanan herhangi bir hizmetle enjekte edilebilir - herhangi bir kısıtlama yoktur ( burada listelenen configve runfarklılıklar dışında ).


6
Vaov! bu kadar ayrıntılı cevap vermeye zaman ayırdığınız için teşekkür ederiz! Bunu iki kez okudum ve sanırım biraz anladım. Bunu ve bugün daha sonra ayrıntılı olarak verdiğiniz bağlantıları inceleyeceğim. Ve kedi için bir +1 daha. :)
user1527166

18
Karşılaştığım en kullanışlı ve ayrıntılı SO cevaplarından biri - teşekkürler!
Godders

11
Bu cevap yeni bir harika seviyesi tanımlar. Aydınlatıcı şeyler.
Ngure Nyaga

4
AngularJS için bugüne kadar karşılaştığım en iyi kaynak. Teşekkürler.
code90

5
Kelimenin tam anlamıyla AngularJS belgelerinin en iyi parçası gördüm. Gitme zamanı!
Iain Duncan

13

BinaryMuse'un sağlayıcılar, fabrikalar ve hizmetler hakkındaki inanılmaz cevabında aynı şey son derece önemli.

Aşağıda, görsel olarak onun noktasını gösterebileceğini düşündüğüm bir görüntü var:

AngularJS hepsi sadece sağlayıcı
(kaynak: simplygoodcode.com )


7

Michelle'in harika cevabı. Sadece direktiflerin uygulanabileceğini belirtmek istiyorum . Adında bir direktifiniz myThingvarsa, aşağıdakileri enjekte edebilirsiniz myThingDirective: İşte anlaşmalı bir örnek .

Yukarıdaki örnek çok pratik değildir, ancak bir direktif enjekte etme yeteneği, bu direktifi dekore etmek istediğinizde yararlıdır .


Bu yönergeyi süsleyen ikinci örnek Açısal 1.4'ten beri işe yaramıyor gibi görünüyor . ( Juan Biscaia'nın yorumuna bakın )
Vadorequest
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.