İSTİSNA: Tüm parametreler çözülemiyor


431

Angular 2'de temel bir uygulama oluşturdum, ancak bileşenlerimden birine bir hizmet enjekte edemediğim garip bir sorunla karşılaştım. Bununla birlikte, oluşturduğum diğer üç bileşenden herhangi birine ince bir şekilde enjekte eder.

Yeni başlayanlar için bu hizmet:

import { Injectable } from '@angular/core';

@Injectable()
export class MobileService {
  screenWidth: number;
  screenHeight: number;

  constructor() {
    this.screenWidth = window.outerWidth;
    this.screenHeight = window.outerHeight;

    window.addEventListener("resize", this.onWindowResize.bind(this) )
  }

  onWindowResize(ev: Event) {
    var win = (ev.currentTarget as Window);
    this.screenWidth = win.outerWidth;
    this.screenHeight = win.outerHeight;
  }

}

Ve çalışmayı reddettiği bileşen:

import { Component, } from '@angular/core';
import { NgClass } from '@angular/common';
import { ROUTER_DIRECTIVES } from '@angular/router';

import {MobileService} from '../';

@Component({
  moduleId: module.id,
  selector: 'pm-header',
  templateUrl: 'header.component.html',
  styleUrls: ['header.component.css'],
  directives: [ROUTER_DIRECTIVES, NgClass],
})
export class HeaderComponent {
  mobileNav: boolean = false;

  constructor(public ms: MobileService) {
    console.log(ms);
  }

}

Tarayıcı konsolunda aldığım hata şudur:

İSTİSNA: HeaderComponent: (?) İçin tüm parametreler çözülemiyor.

Bu yüzden bir sağlayıcı var bootstrap işlevinde hizmet var. Ve bunu herhangi bir bileşenimin yapıcısına sorunsuz bir şekilde enjekte edebiliyor gibiyim.


14
Belki ithalat? Mı '../'bir index.ts(Namlu)? Bunun yerine doğrudan bildirildiği dosyadan içe aktarmayı deneyebilir misiniz?
Günter Zöchbauer

Mucizevi bir şekilde bu düzeltilmiş gibi görünüyor! Hizmeti test ettiğim diğer bileşenler yaptıklarında namluyu kullanmayacaktı. Bunu yorum yerine cevap olarak göndermek istiyorsanız kabul edeceğim.
Keith Otto

11
Genellikle dairesel bir bağımlılık.
Gary

Dairesel bağımlılıkla ilgili bu sorunu yaşadım. Web paketinin daha yeni sürümlerinin bunu söylemede çok daha iyi olduğunu belirtmek gerekir
Enn

Dairesel bağımlılık gibi görünüyor, eğer açısal> = 4 kullanıyorsanız intex.ts (varil) 'den kurtulabilir ve ihtiyacınız olan her şeyi doğrudan alabilirsiniz.
Rammgarot

Yanıtlar:


457

Varil yerine doğrudan bildirildiği dosyadan içe aktarın.

Soruna tam olarak neyin neden olduğunu bilmiyorum ama birkaç kez bahsettiğini gördüm (muhtemelen bir çeşit dairesel bağımlılık).

Ayrıca, namludaki ihracatın sırasını değiştirerek de düzeltilebilir olmalıdır (detayları bilmiyorum, ama bundan da bahsedildi)


16
örneğin, önce bir varilin önce gelmesi gereken başka bir servise enjekte edilmiş bir servisiniz varsa bu doğrudur.
Joao Garin

17
Angular2 ekibi, bu tür birçok sorun nedeniyle artık varil önermiyor. Yardım edebileceğimi duyduğuma sevindim :)
Günter Zöchbauer

13
Angular 2 ekibinin varil önermediğini bilmiyordum. Eğer öyleyse, terimler sözlüğünde yararlarını tartıştığını belirtmelidirler. Ve açısal2-webpack-starter gibi projeler bunları kullanmamalıdır.
Blue

3
Bu düzeltildi dikişler (bir sorun değil 2.0.2). Varilleri, özellikle farklı modüller arasında birkaç model ve hizmet almam gerektiğinde, hala kullanışlı buluyorum. Bu import { cleanValues, getState, FirebaseService, NotificationService, ... } from '../../shared/services';işe yaramadığında bir NgModule
acıydı

3
Argghh Varil (index.ts) dosyasındaki ihracat sırasını değiştirerek çözdüm .. çok teşekkür ederim
Spock

331

Daha önce verilen cevaplara ek olarak, enjekte edilebilir servisiniz gerçek @Injectable()dekoratörü kaçırdığında da bu hata atıldı . Dolayısıyla, döngüsel bağımlılık olayını ve ithalat / ihracat siparişinizin hatalarını ayıklamadan önce, hizmetinizin gerçekten @Injectable()tanımlanmış olup olmadığını basit bir şekilde kontrol edin .

Bu, geçerli Açısal en son Açısal 2.1.0 için geçerlidir.

Bu konuda bir konu açtım .


Evet, bu hata genellikle @Injectable eklemeyi unutmuş olmanızdır ve örneğin Router'@ açısal / yönlendirici' den içe aktarıyor olabilirsiniz ve bu enjektabl olmadan, bu hata her zaman gerçekleşir (bir satır yapmaya karar verdiğinizde) kod enjekte o yönlendirici kullanın
Eric Bishard

Müthiş cevap, benim sorunum hizmetime bir yöntem ekledim ve son parantez sonra bir yarım kolon eklemedim oldu. Neden bu şekilde olması gerektiğine dair hiçbir fikrim yok, ancak bileşen sınıflarında durum böyle değil ... şimdilik sadece ilerlemeye sevindim!
egimaben

Bana bu hatayı veren basit bir modelim vardı. Model yapıcısında özelliklerinizi oluşturduğunuz kısayolu kullandım. Özelliklerin türleri yalnızca string ve int idi. Sonra aniden bu sorun ortaya çıkmaya başladı. @Injectable () eklemek sorunu çözdü. Tuhaf çünkü diğer modellerimin hiçbiri Enjektabl eklemedi. Bu yeni modeli eklemeden önce birkaç kütüphaneyi yükselttiğimi eklemeliyim. Muhtemelen bununla bir ilgisi vardı, ama şimdi çalışıyor. Teşekkürler.
Moutono

@Moutono Doğru. Hizmetinizde boş bir kurucu ile, bağımlılık enjeksiyonu tetiklenmiyor gibi görünüyor ve @injectable()gerekli değil. Bu da kendi başına başka bir tuhaflık. İyi bir önlem için, yine de bir şey enjekte etmeye karar vermeniz gerektiğinde ekleyeceğim.
JP ten Berge

Hizmetinizin de @Injectable () ile dekore edilmesi gereken bir temel sınıf varsa
Sam Shiles

110

Açısal olarak 2.2.3, forwardRef()henüz tanımlanmamış sağlayıcıları enjekte etmenizi sağlayan bir yardımcı program işlevi vardır.

Tanımlanmadığında, bağımlılık enjeksiyon haritasının tanımlayıcıyı bilmediğini kastediyorum. Dairesel bağımlılıklar sırasında olan şey budur. Açısal'da çözülmesi ve görülmesi çok zor olan dairesel bağımlılıklarınız olabilir.

export class HeaderComponent {
  mobileNav: boolean = false;

  constructor(@Inject(forwardRef(() => MobileService)) public ms: MobileService) {
    console.log(ms);
  }

}

@Inject(forwardRef(() => MobileService))Orijinal sorunun kaynak kodunda yapıcı parametresine eklemek sorunu çözecektir.

Referanslar

Açısal 2 Manuel: ForwardRef

İleri referanslar in Angular 2


3
forwardRef()alfa ;-) zaten vardı Sadece Mobilehizmet aynı dosyada daha aşağı ilan edildiğinde gereklidir . Sınıflar farklı dosyalardaysa, buna gerek yokturforwardRef()
Günter Zöchbauer

4
Günter Zöchbauer, hala kodumla ilgili gerçek sorunu anlamaya çalışıyorum, ancak bu arada mesajdan forwardRef()kurtulmaya yardımcı oldu Can't resolve all parameters for .... Soruna daha iyi bir çözüm ararken en azından bileşen çalışıyor. (Ve evet, başarısız bağımlılık doğrudan dosyasından içe aktarılır)
Nik

4
@ GünterZöchbauer Cevabımı referanslarla güncelledim. Cevabınızdan uzaklaşmaya çalışmıyorum, ama bu aslında sorunu çözüyor ve insanların bunu bilmesi gerekiyor. Soruyu Google'da kullanırsanız, kullanacağınızı söyleyen sonuç yoktur forwardRef. Bulmak çok zor. Bu sorunu çözmek için dün bütün gün aldım.
Reactgular

Tuhaf. foreardRefKendimi kullanmayı öneren en az bir düzine cevap yayınladım, ancak daha sonra NgModuletanıtıldı. Temsilcileri kaybetme konusunda endişelenmiyorum. Birkaç aydan beri artık ortaya çıkmadığında neden bununla karşılaştığınızı merak ediyorum. Birkaç gün içinde eve döndüğümde daha yakından bakacağım. Geri bildiriminiz için çok teşekkürler.
Günter Zöchbauer

2
Birisi de içe aktarma konusunda kaybolursa: {@ Component, Inject, ForwardRefFn, forwardRef} '@ angular / core' dan içe aktarılır;
Natanael

69

YANLIŞ # 1: Dekoratörü Unutmak:

//Uncaught Error: Can't resolve all parameters for MyFooService: (?).
export class MyFooService { ... }

YANLIŞ # 2: "@" Sembolünü atlamak:

//Uncaught Error: Can't resolve all parameters for MyFooService: (?).
Injectable()
export class MyFooService { ... }

YANLIŞ # 3: "()" Sembollerini Atlama:

//Uncaught Error: Can't resolve all parameters for TypeDecorator: (?).
@Injectable
export class MyFooService { ... }

YANLIŞ # 4: Küçük harf "i":

//Uncaught ReferenceError: injectable is not defined
@injectable
export class MyFooService { ... }

YANLIŞ # 5: Unuttun: {Enjektabl} '@ açısal / çekirdek'ten içe aktar;

//Uncaught ReferenceError: Injectable is not defined
@Injectable
export class MyFooService { ... }

DOĞRU:

@Injectable()
export class MyFooService { ... }


21

Ayrıca, A hizmetini B hizmetine enjekte ederek ya da tam tersini yaparak karşılaştım.

Herhalde kaçınılması gerektiği için bunun hızlı bir şekilde başarısız olması iyi bir şey . Hizmetlerinizin daha modüler ve yeniden kullanılabilir olmasını istiyorsanız, döngüsel referanslardan mümkün olduğunca kaçınmak en iyisidir. Bu yazı bunu çevreleyen tuzakları vurgular.

Bu nedenle, aşağıdaki önerilere sahibim:

  • Sınıfların çok sık etkileşime girdiğini düşünüyorsanız ( özellik kıskançlığından bahsediyorum ), 2 hizmeti 1 sınıfa birleştirmeyi düşünebilirsiniz .
  • Yukarıdaki işi sizin için değilse, bir kullanmayı düşünün 3 hizmetini , (bir EventServiceiki hizmet alışverişi mesajlar için enjekte olabilir).

1
Kesinlikle başıma gelen bu oldu ve bu da devam etmenin yolu. Güncelleme gerektiren birden fazla hizmetiniz olduğunu biliyorsanız, EventService kullanın. Uygulamayı bu olaylara dayalı olarak genişletirken şüphesiz bu olaylara dokunmanız gerekeceğinden daha da genişletilebilir.
themightybun

17

Arama yapanların yararına; Bu hatayı aldım. Basitçe eksik bir @ simgesiydi.

Ie Bu Can't resolve all parameters for MyHttpServicehatayı üretir .

Injectable()
export class MyHttpService{
}

Eksik @sembolü eklemek sorunu çözer.

@Injectable()
export class MyHttpService{
}

2
Benim durumumda, @Injectable ve hizmet sınıfı tanımı arasında ekstra sınıflar ve arabirimler ekledim, bu nedenle hizmet sınıfı artık enjekte edilebilir olarak işaretlenmedi.
Herc

Diğer enjekte edilebilir hizmetleri tüketen bir hizmet sınıfındaki @Injectable () dekoratörünü tamamen unutursanız, yanlış dekore edilmiş hizmetiniz de bu hatayı atar.
I. Buchan

10

Benim durumumda, iş import "core-js/es7/reflect";yapmak için başvuruma eklemem gerekiyordu @Injectable.


9

Başka bir olasılık emitDecoratorMetadatatsconfig.json içinde true değerine ayarlanmamıştır

{
  "compilerOptions": {

     ...

    "emitDecoratorMetadata": true,

     ...

    }

}

8

Eğer hizmet varsa bu hatayı alıyorum A bir bağlıdır statik özellik / yöntemin hizmeti ait B ve hizmet B kendisi hizmet bağlıdır A oluk bağımlılık enjeksiyon. Dolayısıyla, özellik / yöntem statik olduğu için olmasa da, bir tür dairesel bağımlılıktır. Muhtemelen AOT ile birlikte oluşan bir hata .


Aynı dosyada tanımlanan bir işleve bağımlılık olduğunda da yaşadım. Ayrı bir dosyaya bölmek sorunu çözdü.
Joe

1
Bahsettiğiniz için teşekkürler. Kendimi tam olarak buldum. Statik sınıflara doğrudan erişmenin DI ile bir ilgisi olabileceğini fark etmedim. Bu şema vardı: A -> Bve her ikisi de aynı statik sınıfı kullanıyordu. Çözümü forwardRefyardımcı olur, ancak bunun nasıl çözüleceğine bakacağım. Muhtemelen bu statik sınıftan gerçek bir hizmet yapmaya çalışacağım (bu da daha iyi bir tasarıma yol açacaktır).
Slava Fomin II

8

Kayıp @Injectable()dekoratöre ek olarak

@Injectable()Soyut sınıfta eksik dekoratör üretildi Hizmet için tüm parametreler çözülemiyor: (?) Dekoratörün MyServicetüretilmiş sınıfta olduğu gibi mevcut olması gerekirBaseService

//abstract class
@Injectable()
abstract class BaseService { ... }

//MyService    
@Injectable()
export class MyService extends BaseService {
.....
}

7

Benim durumumda, bir yapıcı parametresi için tür bildirmediğim için oldu.

Ben böyle bir şey vardı:

constructor(private URL, private http: Http) { }

ve aşağıdaki kodla değiştirmek sorunumu çözdü.

constructor(private URL : string, private http: Http) {}

5

benim için sadece ()@Injectable eksikliği vardı. Uygun @Injectable ()


Ya da benim durumumda yanlışlıkla @
TDP'yi

4

Enjekte edilebilir yapıcı () yönteminden parametreleri kaldırmak benim durumum için çözdü.


Bu da benim sorunumdu. Göndermeye geldim ama önce yaptığını buldum! +1
aesede

sonra nasıl yeniden kullanılabilir hizmet parametreleri göndermek için?
3gwebtrain


2

Benim için sorun daha da sinir bozucuydu, bir hizmet içinde bir hizmet kullanıyordum ve appModule'de bağımlılık olarak eklemeyi unuttum! Bu birisinin sadece tekrar kurmak için uygulamayı bozarak birkaç saat kazanmasına yardımcı olmasını umuyoruz


1
Sadece bir @Injectek açıklama eksikti . Hata mesajının ne dediğini tam olarak gözden kaçırıyordum. Dairesel bağımlılıklardan şüphelenmiyorsanız, yalnızca hatada belirtilen sınıfa gidin ve tüm yapıcı parametrelerine ve açıklamalı tüm sınıf üyelerine bakın ve hepsinde @InjectDI yaptığınızdan emin olun. Burada DI hakkında daha fazla bilgi: angular.io/docs/ts/latest/guide/dependency-injection.html
Alexander Taylor

2

@Component dekoratörüne veya bileşeninizin bildirildiği modüle sağlayıcılar dizisi eklemeniz gerekir. İç bileşen şunları yapabilirsiniz:

@Component({
  moduleId: module.id,
  selector: 'pm-header',
  templateUrl: 'header.component.html',
  styleUrls: ['header.component.css'],
  directives: [ROUTER_DIRECTIVES, NgClass],
  providers: [MobileService]
})

2

Benim durumumda yapıcı yanlış parametreler geçirerek bu hatayı üretir, bu hata hakkında temel fikir bilmeden herhangi bir fonksiyona bazı yanlış argümanlar geçirmiş olmasıdır.

export class ProductComponent {
    productList: Array<Product>;

    constructor(productList:Product) { 
         // productList:Product this arg was causing error of unresolved parameters.
         this.productList = [];
    }
}

Bunu sadece bu argümanı kaldırarak çözdüm.


2

Benim için, polyfills.ts dosyasında bu içe aktarmayı yanlışlıkla devre dışı bıraktığımda bu hatayı aldım, bu hatayı önlemek için içe aktarıldığından emin olmanız gerekir.

/** Evergreen browsers require these. **/
// Used for reflect-metadata in JIT. If you use AOT (and only Angular decorators), you can remove.
import 'core-js/es7/reflect';

2

Benim durumumda NativeDateAdapter" format(date: Date, displayFormat: Object)" yöntemini geçersiz kılmak için " " genişletmeye çalışıyordum .

AngularMaterial-2 DatePicker öğesinde.

Temelde açıklama eklemek unuttum @Injectable.

Bunu "CustomDateAdapter" sınıfına ekledikten sonra:

@Injectable({
  providedIn: 'root'
})

Hata gitti.


Bu benim için çalıştı, ama neden olduğu hakkında hiçbir fikrim yok. DI'nin çalışması için hem hizmetin hem de DI yoluyla alınan bileşenin sağlanması gerekiyor mu?
Mike Furlender

2

Bu yanıt bu sorun için çok yararlı olabilir. Ayrıca, benim durumum için default, neden olarak hizmet ihracat .

YANLIŞ:

@Inject()
export default class MobileService { ... }

DOĞRU:

@Inject()
export class MobileService { ... }

2

Bu, hatadaki geri bildirim eksikliğinden dolayı hata ayıklamak için gerçekten zor bir sorun olabilir. Gerçek bir döngüsel bağımlılıktan endişe ediyorsanız, yığın izlemesinde bakmanız gereken en önemli şey a) hizmetin adı b) bu ​​hizmette soru işareti olan yapıcı parametresi, örneğin şu şekilde görünüyorsa:

AuthService için tüm parametreleri çözemezsiniz: ([object Object], [object Object], [object Object], [object Object],?)

5. parametrenin AuthService'e de bağlı olan bir hizmet olduğu anlamına gelir. yani soru işareti, DI tarafından çözülmediği anlamına gelir.

Oradan, kodu yeniden yapılandırarak 2 hizmeti ayırmanız yeterlidir.


1

Hizmetin adını, yani yapıcı (özel myService: MyService ) yanlış yazarak bu hatayla karşılaştım .

Yanlış yazılmış hizmetler için, sayfayı Chrome-> Konsol'da inceleyerek hangi hizmetin sorun olduğunu belirleyebildim (yapıcıda birkaç tane listeledim). Object, object Object,? Nesnesini görüntüleyerek iletinin bir parçası olarak "parametre" dizi listesini göreceksiniz. (ya da böyle bir şey). Nerede "?" ve soruna neden olan hizmetin konumudur.


1

Sipariş rağmen boruları içinde dışa sınıfları söz edilmiş olabilir, şu senaryo, aynı etkiyi üretebilir.

Eğer sınıfları olduğunu varsayalım A, Bve Caynı dosya içinde ihraç Abağlıdır Bve C:

@Injectable()
export class A {
    /** dependencies injected */
    constructor(private b: B, private c: C) {}
}

@Injectable()
export class B {...}

@Injectable()
export class C {...}

Beri bağımlı (bu durumda sınıflarında yani sınıflar Bve C) henüz (açısal, bilinmemektedir sınıfına açısal bağımlılığı enjeksiyon işlemi sırasında muhtemelen çalışma anındaA ) hata ortaya çıkar.

Çözüm

Çözüm, DI'nin yapıldığı sınıftan önce bağımlı sınıfları beyan etmek ve ihraç etmektir.

yani yukarıdaki durumda sınıf A, bağımlılıkları tanımlandıktan hemen sonra bildirilir:

@Injectable()
export class B {...}

@Injectable()
export class C {...}

@Injectable()
export class A {
    /** dependencies injected */
    constructor(private b: B, private c: C) {}
}

1

Benim durumumda, aynı bileşen dosyasından bir Sınıf ve bir Numaralandırma verdim:

mComponent.component.ts:

export class MyComponentClass{...}
export enum MyEnum{...}

Sonra MyEnumbir çocuktan kullanmaya çalışıyordum MyComponentClass. Tüm parametreler çözülemedi hatasına neden oluyordu .

Konumundan MyEnumayrı bir klasöre taşınarak MyComponentClasssorunum çözüldü!

Günter Zöchbauer'in belirttiği gibi, bu bir servis veya bileşen dairesel olarak bağımlı olduğu için oluyor.


1

Hizmetiniz bir bileşenle aynı dosyada tanımlanıyorsa (onu tüketir) ve hizmet daha sonra tanımlanırsa dosyadaki bileşenden bu hatayı alabilirsiniz. Bu, diğerlerinin bahsettiği aynı 'forwardRef' sorunundan kaynaklanmaktadır. Şu anda VSCode size bu hatayı göstermek konusunda büyük değildir ve derleme başarıyla derlenir.

Derlemenin çalıştırılması, --aotderleyicinin çalışma şekli nedeniyle bu sorunu maskeleyebilir (muhtemelen ağaç sallama ile ilgili).

Çözüm: Hizmetin başka bir dosyada veya bileşen tanımından önce tanımlandığından emin olun. (Bu durumda forwardRef'in kullanılabileceğinden emin değilim, ama bunu yapmak beceriksiz görünüyor).

Eğer çok güçlü bir bileşene (görünüm modeli gibi bir tür) bağlı çok basit bir hizmet varsa - örn. ImageCarouselComponent, Adlandırabilirim, ImageCarouselComponent.service.tsböylece diğer hizmetlerimle karıştırılmaz.


1

Benim durumumda dairesel bir referanstı. MyService'i Myservice2 ve MyService2'yi MyService olarak çağırdım.

İyi değil :(


1

Benim durumumda sebep şuydu:

  • enjekte edilebilir servisim A başka bir B sınıfı genişletti
  • B'nin argüman gerektiren bir kurucusu vardı
  • A'da hiçbir kurucu tanımlamamıştım

Sonuç olarak, bir nesne A oluşturmaya çalışırken, varsayılan yapıcı başarısız oldu. Bunun neden derleme hatası olmadığı hakkında hiçbir fikrim yok.

A'ya B'nin yapıcısını doğru şekilde adlandıran bir yapıcı ekleyerek düzelttim.


1

Anladım!

Yukarıdaki yanıtlardan hiçbiri size yardımcı olmadıysa, belki aynı dosyadan bir öğe içe aktarıyorsunuzdur bir bileşenin hizmeti enjekte ettiği .

Daha iyi açıklarım:

Hizmet dosyası :

// your-service-file.ts
import { helloWorld } from 'your-component-file.ts'

@Injectable()
export class CustomService() {
  helloWorld()
}

Bu bileşen dosyasıdır :

@Component({..})
export class CustomComponent {
  constructor(service: CustomService) { }
}

export function helloWorld() {
  console.log('hello world');
}

Bu nedenle, sembol aynı bileşenin içinde değil, aynı dosyanın içinde olsa bile sorunlara neden olur. Sembolü başka bir yere taşıyın (bir işlev, sabit, sınıf vb. Olabilir) ve hata kaybolur


1

açısal 6 ve daha yeni sürümler için deneyin

@Injectable({
  providedIn: 'root'
})

.. servis sınıfınızın hemen üzerinde, aralarında başka satır yok

avantajları

  • hizmeti herhangi bir modüle eklemenize gerek yok ("otomatik olarak keşfedilecek")
  • hizmet tekil olacaktır (kök içine enjekte edileceğinden)

[ açısal dokümanlar ]

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.