WYJĄTEK: nie można rozwiązać wszystkich parametrów

431

Zbudowałem podstawową aplikację w Angular 2, ale napotkałem dziwny problem, w którym nie mogę wstrzyknąć usługi do jednego z moich komponentów. Jednak wstrzykuje się dobrze w którykolwiek z trzech innych komponentów, które stworzyłem.

Na początek jest to usługa:

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

}

A komponent, z którym odmawia współpracy:

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

}

Występuje błąd w konsoli przeglądarki:

WYJĄTEK: nie można rozwiązać wszystkich parametrów dla HeaderComponent: (?).

Mam usługę w funkcji bootstrap, więc ma dostawcę. I wydaje mi się, że jestem w stanie wstrzyknąć go do konstruktora dowolnego z moich innych komponentów bez problemu.

Keith Otto
źródło
14
Może import? Czy (Beczka)? Czy zamiast tego możesz spróbować zaimportować go z pliku, w którym został zadeklarowany bezpośrednio? '../'index.ts
Günter Zöchbauer
Cudem wydaje się, że to naprawiło! Dziwne, że nie działałoby to przy użyciu lufy, gdy działały inne komponenty, z którymi testowałem usługę. Jeśli chcesz zamieścić to jako odpowiedź zamiast komentarza, zaakceptuję.
Keith Otto
11
Zasadniczo zależność cykliczna.
Gary,
Mam również ten problem z zależnością cykliczną. Warto zauważyć, że nowsze wersje pakietu internetowego są znacznie lepsze w informowaniu o tym
En
Wygląda na zależność cykliczną. Jeśli użyjesz wartości kątowej> = 4, możesz pozbyć się intex.ts (baryłki) i zaimportować wszystko, czego potrzebujesz bezpośrednio.
Rammgarot

Odpowiedzi:

457

Zaimportuj go z pliku, w którym jest zadeklarowany bezpośrednio zamiast beczki.

Nie wiem, co dokładnie powoduje problem, ale widziałem to kilka razy (prawdopodobnie pewną zależność cykliczną).

Powinien być również naprawiony poprzez zmianę kolejności eksportu w beczce (nie znam szczegółów, ale został również wspomniany)

Günter Zöchbauer
źródło
16
jest to poprawne, jeśli masz na przykład usługę wstrzykniętą do innej usługi, która najpierw musi być pierwsza w beczce.
Joao Garin
17
Zespół Angular2 nie zaleca już beczek z powodu wielu takich problemów. Cieszę się, że mogłem pomóc :)
Günter Zöchbauer
13
Nie wiedziałem, że zespół Angular 2 nie zaleca beczek. Jeśli tak, powinni zauważyć, że w glosariuszu omawiającym ich zalety. Projekty takie jak angular2-webpack-starter nie powinny ich używać.
Niebieski,
3
Wygląda na to, że zostało to naprawione (nie jest to problem 2.0.2). Uważam, że beczki są nadal przydatne, zwłaszcza gdy muszę zaimportować kilka modeli i usług między różnymi modułami. To import { cleanValues, getState, FirebaseService, NotificationService, ... } from '../../shared/services';był ból, kiedy to nie działało (; NgModulenie pomaga w usługach singletonowych ...
Sasxa,
3
Argghh Rozwiązałem go, zmieniając kolejność eksportu w pliku beczki (index.ts) .. dziękuję bardzo
Spock
331

Oprócz wcześniejszych odpowiedzi wydaje się, że ten błąd jest zgłaszany również wtedy, gdy usługa wstrzykiwania nie ma rzeczywistego @Injectable()dekoratora. Dlatego przed debugowaniem kwestii cyklicznej zależności i kolejności importu / eksportu należy po prostu sprawdzić, czy usługa faktycznie @Injectable()zdefiniowała.

Dotyczy to aktualnej wersji Angular, Angular 2.1.0.

Otworzyłem problem w tej sprawie .

JP ten Berge
źródło
Tak, ten błąd jest zwykle spowodowany tym, że zapomniałeś dodać @Injectable i na przykład możesz po prostu importować Routerz „@ angular / router” i bez tego iniekcji ten błąd będzie się zawsze pojawiał (jak tylko zdecydujesz się wprowadzić jedną linię użyj kodu, który wstrzyknął router
Eric Bishard,
Niesamowita odpowiedź, moim problemem było to, że dodałem metodę w mojej usłudze i nie dodałem średnika po ostatnim nawiasie klamrowym. Nie mam pojęcia, dlaczego tak jest, ale nie jest tak w klasach komponentów ... na razie cieszę się, że mogę przejść dalej!
egimaben
Miałem prosty model, który dał mi ten błąd. Użyłem skrótu, w którym tworzysz swoje właściwości w konstruktorze modelu. Typami właściwości były tylko string i int. Nagle ten problem zaczął się pojawiać. Dodanie @Injectable () rozwiązało problem. Dziwne, ponieważ żaden z moich innych modeli nie ma wstrzykiwanego. Muszę dodać, że zaktualizowałem sporo bibliotek przed dodaniem tego nowego modelu. Być może miało to coś wspólnego, ale teraz działa. Dzięki.
Moutono
@Moutono poprawnie. Przy pustym konstruktorze w Twojej usłudze wstrzykiwanie zależności wydaje się nie być uruchamiane i @injectable()nie jest wymagane. Co jest kolejną osobliwością samą w sobie. Na wszelki wypadek nadal to dodam, po prostu na czas, kiedy powinieneś zdecydować się na zastrzyk.
JP ten Berge
Pamiętaj, że jeśli twoja usługa ma klasę podstawową, która również musi być ozdobiona @Injectable ()
Sam Shiles,
110

Od Angular 2.2.3dostępna jest teraz forwardRef()funkcja narzędzia, która pozwala wstrzykiwać dostawców, którzy nie zostali jeszcze zdefiniowani.

Przez niezdefiniowane rozumiem, że mapa wstrzykiwania zależności nie zna identyfikatora. Tak dzieje się podczas zależności cyklicznych. W Angular możesz mieć zależności kołowe, które bardzo trudno jest rozplątać i zobaczyć.

export class HeaderComponent {
  mobileNav: boolean = false;

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

}

Dodanie @Inject(forwardRef(() => MobileService))do parametru konstruktora w kodzie źródłowym pierwotnego pytania naprawi problem.

Bibliografia

Instrukcja Angular 2: ForwardRef

Przekaż referencje w Angular 2

Reactgular
źródło
3
forwardRef()był już w wersji alfa ;-) Jest potrzebny tylko wtedy, gdy Mobileusługa jest zadeklarowana w dalszej części tego samego pliku. Jeśli klasy znajdują się w różnych plikach, nie ma potrzebyforwardRef()
Günter Zöchbauer,
4
Günter Zöchbauer, wciąż próbuję znaleźć prawdziwy problem z moim kodem, ale tymczasem forwardRef()pomogłem pozbyć się Can't resolve all parameters for ...wiadomości. Przynajmniej składnik działa, kiedy szukam lepszego rozwiązania problemu. (I tak, zależność od awarii jest importowana bezpośrednio z jej pliku)
Nik
4
@ GünterZöchbauer Zaktualizowałem odpowiedź o referencje. Nie próbuję odbierać twojej odpowiedzi, ale to faktycznie rozwiązuje problem i ludzie muszą o tym wiedzieć. Jeśli google pytanie, nie ma wyników, które mówią, aby użyć forwardRef. Bardzo trudno go znaleźć. Wczoraj zajęło mi cały dzień, aby rozwiązać ten problem.
Reactgular,
Dziwne. Zamieściłem co najmniej tuzin odpowiedzi, które sugerują użycie foreardRefsiebie, ale już nie później NgModule. Nie martwię się o utratę przedstawicieli. Jestem tylko ciekawy, dlaczego się na to natknąłeś, gdy nie pojawił się już od kilku miesięcy. Przyjrzę się bliżej, kiedy wrócę do domu za kilka dni. Wielkie dzięki za opinie.
Günter Zöchbauer,
2
Jeśli ktoś również zgubił się na temat importu: import {Component, Inject, ForwardRefFn, forwardRef} z '@ angular / core';
Natanael
69

ŹLE # 1: Zapominanie o Dekoratorze:

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

ŹLE # 2: Pominięcie symbolu „@”:

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

ŹLE # 3: Pominięcie symboli „()”:

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

ŹLE # 4: Małe litery „i”:

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

ŹLE # 5: Zapomniałeś: import {Injectable} z '@ angular / core';

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

POPRAWNY:

@Injectable()
export class MyFooService { ... }
JMI MADISON
źródło
27

Jak już wspomniano, problem jest spowodowany zamówieniem eksportu w beczce, który jest spowodowany zależnościami cyklicznymi.

Bardziej szczegółowe wyjaśnienie znajduje się tutaj: https://stackoverflow.com/a/37907696/893630

Michał
źródło
3
Zamawianie nie rozwiązało mojego problemu. Nie używał beczki.
Michael Laffargue
21

Zetknąłem się również z tym, wstrzykując usługę A do usługi B i odwrotnie.

Myślę, że to dobrze, że szybko się to nie udaje, bo i tak powinno się go unikać . Jeśli chcesz, aby Twoje usługi były bardziej modułowe i nadawały się do ponownego wykorzystania, najlepiej unikać w miarę możliwości odwołań cyklicznych. Ten post podkreśla pułapki, które go otaczają.

Dlatego mam następujące zalecenia:

  • Jeśli uważasz, że klasy zbyt często wchodzą w interakcje (mówię o zazdrości o funkcje ), możesz rozważyć połączenie 2 usług w 1 klasę .
  • Jeśli powyższe nie działa, rozważ skorzystanie z trzeciej usługi (an EventService), którą obie usługi mogą wprowadzić w celu wymiany wiadomości.
Stephen Paul
źródło
1
To na pewno mi się przydarzyło i tak właśnie należy postępować. Jeśli wiesz, że masz więcej niż jedną usługę wymagającą aktualizacji, skorzystaj z usługi EventService. Jest to bardziej rozszerzalne, ponieważ bez wątpienia będziesz musiał korzystać z tych wydarzeń podczas rozszerzania aplikacji na podstawie tych zdarzeń.
themightybun
17

Z korzyścią dla poszukiwaczy; Mam ten błąd. To był po prostu brakujący symbol @.

Tj. To powoduje Can't resolve all parameters for MyHttpServicebłąd.

Injectable()
export class MyHttpService{
}

Dodanie brakującego @symbolu naprawia go.

@Injectable()
export class MyHttpService{
}
Hokej
źródło
2
W moim przypadku dodałem dodatkowe klasy i interfejsy między @Injectable a definicją klasy usługi, więc klasa usługi nie była już oznaczana jako wstrzykiwana.
Herc
Jeśli całkowicie zapomnisz dekorator @Injectable () w klasie usług, która korzysta z innych usług do wstrzykiwania, wówczas niewłaściwie udekorowana usługa również zgłosi ten błąd.
I. Buchan,
10

W moim przypadku musiałem dodać import "core-js/es7/reflect";do mojej aplikacji, aby @Injectabledziałać.

AJ Richardson
źródło
9

Inną możliwością nie jest emitDecoratorMetadataustawienie wartości true w pliku tsconfig.json

{
  "compilerOptions": {

     ...

    "emitDecoratorMetadata": true,

     ...

    }

}
Stewart_R
źródło
8

Ten błąd występuje, jeśli masz usługę A, która zależy od właściwości statycznej / metody usługi B, a sama usługa B zależy od wstrzyknięcia zależności usługi A do koryta. Jest to więc rodzaj zależności cyklicznej, chociaż nie jest tak, ponieważ właściwość / metoda jest statyczna. Prawdopodobnie błąd występujący w połączeniu z AOT .

MK
źródło
Miałem to również wtedy, gdy istnieje zależność od funkcji po prostu zdefiniowanej w tym samym pliku. Naprawiono dzielenie go na osobny plik.
Joe
1
Dziękuję, że o tym wspomniałeś. Znalazłem się w dokładnej sytuacji. Nie zdawałem sobie sprawy, że bezpośredni dostęp do klas statycznych może mieć coś wspólnego z DI. Miałem ten schemat: A -> Bobaj używali tej samej klasy statycznej. Rozwiązanie forwardRefpomaga, ale przyjrzę się, jak można to rozwiązać. Prawdopodobnie postaram się zrobić prawdziwą usługę z tej klasy statycznej (doprowadzi to również do lepszego projektu).
Slava Fomin II
8

Oprócz brakujących @Injectable() dekoratora

Brak @Injectable()dekoratora w klasie abstrakcyjnej spowodował, że nie można rozwiązać wszystkich parametrów usługi: (?) Dekorator musi być obecny MyServicezarówno w klasie pochodnej, jak iBaseService

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

//MyService    
@Injectable()
export class MyService extends BaseService {
.....
}
Bart
źródło
7

W moim przypadku stało się tak, ponieważ nie zadeklarowałem typu parametru konstruktora.

Miałem coś takiego:

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

a następnie zmiana go na poniższy kod rozwiązała mój problem.

constructor(private URL : string, private http: Http) {}
Alf Moh
źródło
5

dla mnie był to po prostu brak ()w @Injectable. Prawidłowe jest @Injectable ()

repo
źródło
Lub w moim przypadku przypadkowe usunięcie @
TDP
4

Usunięcie parametrów z metody iniekcji konstruktora () rozwiązało to w moim przypadku.

Matjaz Hirsman
źródło
To był dokładnie mój problem. Przyszedłem go opublikować, ale odkryłem, że zrobiłeś pierwszy! +1
aesede
jak przesłać parametry do usługi wielokrotnego użytku?
3gwebtrain
2

Cóż, dla mnie problem był jeszcze bardziej irytujący, korzystałem z usługi w ramach usługi i zapomniałem dodać ją jako zależność w module aplikacji! Mam nadzieję, że pomoże to komuś zaoszczędzić kilka godzin na zerwaniu aplikacji, ale tylko do jej ponownego utworzenia

Ophir Stern
źródło
1
Brakowało mi tylko @Injectadnotacji. Przeoczyłem dokładnie to, co mówi komunikat o błędzie. Jeśli nie podejrzewasz zależności cyklicznych, po prostu przejdź do klasy wymienionej w błędzie i spójrz na wszystkie parametry konstruktora i wszystkich członków klasy opatrzonych adnotacjami @Injecti upewnij się, że wykonujesz DI na wszystkich z nich. Więcej na temat DI tutaj: angular.io/docs/ts/latest/guide/dependency-injection.html
Alexander Taylor
2

Musisz dodać tablicę dostawców w dekoratorze @Component lub w module, w którym deklarowany jest twój komponent. Wewnątrz komponentu możesz wykonać następujące czynności:

@Component({
  moduleId: module.id,
  selector: 'pm-header',
  templateUrl: 'header.component.html',
  styleUrls: ['header.component.css'],
  directives: [ROUTER_DIRECTIVES, NgClass],
  providers: [MobileService]
})
Shivang Gupta
źródło
2

W moim przypadku przekazanie niewłaściwych parametrów do konstruktora generuje ten błąd, podstawową ideą tego błędu jest to, że nieświadomie przekazałeś jakieś nieprawidłowe argumenty do dowolnej funkcji.

export class ProductComponent {
    productList: Array<Product>;

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

Rozwiązałem to, po prostu usuwając ten argument.

Codiee
źródło
2

Dla mnie ten błąd wystąpił, gdy przez pomyłkę wyłączyłem ten import w pliku polyfills.ts, musisz się upewnić, że został zaimportowany, aby uniknąć tego błędu.

/** 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';
Ahmed Elkoussy
źródło
2

W moim przypadku próbowałem przedłużyć „ NativeDateAdapter”, aby zastąpić ”format(date: Date, displayFormat: Object) metodę metodę ”.

W AngularMaterial-2 DatePicker.

Zasadniczo więc zapomniałem dodać @Injectableanotację.

Po dodaniu tego do mojej klasy „CustomDateAdapter”:

@Injectable({
  providedIn: 'root'
})

Błąd zniknął.

Muhammed Ozdogan
źródło
To działało dla mnie, ale nie mam pojęcia, dlaczego. Czy zarówno usługa, jak i komponent, który odbiera ją za pośrednictwem DI, muszą być dostarczone w: root, aby DI mógł działać?
Mike Furlender
2

Ta odpowiedź może być bardzo pomocna w przypadku tego problemu. Ponadto w moim przypadku eksport usługi defaultbył przyczyną.

ŹLE:

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

POPRAWNY:

@Inject()
export class MobileService { ... }
otiai10
źródło
2

Może to być bardzo trudny problem do debugowania z powodu braku informacji zwrotnej w błędzie. Jeśli obawiasz się o faktyczną zależność cykliczną, oto najważniejszą rzeczą, na którą należy zwrócić uwagę w stosie a) nazwa usługi b) parametr konstruktora w tej usłudze, który ma znak zapytania, np. Jeśli wygląda tak:

nie można rozwiązać wszystkich parametrów dla usługi AuthService: ([Object Object], [Object Object], [Object Object], [Object Object],?)

oznacza to, że piąty parametr jest usługą zależną również od usługi AuthService. tzn. znak zapytania oznacza, że ​​nie został rozwiązany przez DI.

Stamtąd wystarczy oddzielić 2 usługi, restrukturyzując kod.

sarora
źródło
1

Wystąpił ten błąd przez błędne wpisanie nazwy usługi, tj. Konstruktora (private myService: MyService ).

W przypadku usług z błędami pisarskimi byłem w stanie ustalić, która usługa była problemem (miałem kilka wymienionych w konstruktorze), sprawdzając stronę w Chrome-> Console. Zobaczysz jako część wiadomości listę tablic „parametrów”, wyświetlając obiekt Obiekt, obiekt Obiekt,? (czy jakoś tak). Zauważ, gdzie „?” jest i to jest pozycja usługi, która powoduje problem.

maleman
źródło
1

Chociaż zamawianie można było wspomnieć eksportowanych klas z beczek, poniższy scenariusz może również dać ten sam efekt.

Załóżmy, że masz zajęcia A, Bi Cwywożone ze w tym samym pliku, gdzie Azależy Bi C:

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

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

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

Ponieważ klasy zależne (tj. W tym przypadku klasy Bi C) nie są jeszcze znane Angularowi ( prawdopodobnie w czasie wykonywania podczas procesu wstrzykiwania zależności Angulara do klasyA ) błąd jest zgłaszany.

Rozwiązanie

Rozwiązaniem jest zadeklarowanie i wyeksportowanie klas zależnych przed klasą, w której wykonano DI.

tzn. w powyższym przypadku klasa Ajest zadeklarowana zaraz po zdefiniowaniu jej zależności:

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

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

@Injectable()
export class A {
    /** dependencies injected */
    constructor(private b: B, private c: C) {}
}
Ahmad Baktash Hayeri
źródło
1

W moim przypadku eksportowałem klasę i enum z tego samego pliku komponentu:

mComponent.component.ts:

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

Potem próbowałem użyć MyEnumod dziecka z MyComponentClass. To spowodowało błąd Nie można rozwiązać wszystkich parametrów .

Przeniesienie MyEnumdo osobnego folderu od MyComponentClassrozwiązało mój problem!

Jak wspomniał Günter Zöchbauer, dzieje się tak, ponieważ usługa lub komponent jest zależny cyklicznie.

Menelaos Kotsollaris
źródło
1

Jeśli twoja usługa jest zdefiniowana w tym samym pliku co składnik (który ją zużywa), a usługa jest zdefiniowana później komponencie w pliku, możesz otrzymać ten błąd. Wynika to z tego samego problemu „forwardRef”, o którym wspominali inni. W tej chwili VSCode nie jest świetny w pokazywaniu tego błędu, a kompilacja się kompiluje.

Uruchomienie kompilacji --aotmoże maskować ten problem ze względu na sposób działania kompilatora (prawdopodobnie związany z drżeniem drzewa).

Rozwiązanie: Upewnij się, że usługa jest zdefiniowana w innym pliku lub przed definicją komponentu. (Nie jestem pewien, czy w tym przypadku można użyć forwardRef, ale wydaje się to niezdarne).

Jeśli mam bardzo prostą usługę, która jest bardzo mocno związana z komponentem (coś w rodzaju modelu widoku) - np. ImageCarouselComponent, Mogę to nazwać, ImageCarouselComponent.service.tsżeby nie pomieszało się z moimi innymi usługami.

Simon_Weaver
źródło
1

W moim przypadku było to okrągłe odniesienie. Miałem MyService dzwoniąc do Myservice2 i MyService2 dzwoniąc do MyService.

Niedobrze :(

lucbonnin
źródło
1

W moim przypadku powodem było:

  • moja usługa wstrzykiwania A rozszerzyła kolejną klasę B.
  • B miał konstruktora, który wymagał argumentu
  • Nie zdefiniowałem żadnego konstruktora w A.

W rezultacie próba utworzenia obiektu A nie powiodła się domyślny konstruktor. Nie mam pojęcia, dlaczego nie był to błąd kompilacji.

Naprawiłem to, dodając konstruktor w A, który poprawnie nazwał konstruktorem B.

Vic Seedoubleyew
źródło
1

Gotcha!

Jeśli żadna z powyższych odpowiedzi nie pomogła, być może importujesz jakiś element z tego samego pliku, w którym składnik wstrzykuje usługę.

Wyjaśniam lepiej:

To jest plik usługi :

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

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

To jest plik komponentu :

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

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

Powoduje to problemy, nawet jeśli symbol nie znajduje się w tym samym komponencie, ale tylko w tym samym pliku. Przenieś symbol (może to być funkcja, stała, klasa itd.) W inne miejsce, a błąd zniknie

Cristian Traìna
źródło
1

dla wersji kątowej 6 i nowszych spróbuj

@Injectable({
  providedIn: 'root'
})

.. tuż nad klasą usług, bez żadnych innych linii pośrednich

Zalety

  • nie trzeba dodawać usługi do żadnego modułu (zostanie „automatycznie wykryty”)
  • usługa będzie singletonem (ponieważ zostanie wstrzyknięta do katalogu głównego)

[ dokumenty kątowe ]

lolcatzftw
źródło