Eugene Kirin
Eugene Kirin

Reputation: 578

Angular 7 - build --prod failed with error: Can't resolve all parameters for

I use Angular: 7.2.10 and when I try to build project for production with command:

ng b --prod

I got error

ERROR in : Can't resolve all parameters for ApiService in ...

I have service with a constructor with 3 params:

constructor(api: string, private _http: HttpClient, private httpUtils: HttpUtilsService) {
    this.api = `${api}/api`;        
  }

Which instantiates by factory defined at app.module.ts:

{      
      provide: ApiService,
      useFactory: apiHost,
      deps: [Store, HttpClient, HttpUtilsService]
    }

apiHost

export function apiHost(store: Store<RemoteConfig>, http: HttpClient, httpUtils: HttpUtilsService) {
  let item: string = localStorage.getItem(environment.apiHost);

  //store.pipe(select(backendApiHost), take(1)).subscribe(api => item = api); // Todo not always read val!
  //console.log('ss: ' + item);
  return new ApiService(item, http, httpUtils);
}

When I use ng build it works successfully.

Upvotes: 3

Views: 1780

Answers (3)

Aluan Haddad
Aluan Haddad

Reputation: 31803

Dependencies are implicitly resolved by examining the metadata emitted by the compiler. This metadata is derived from the types of the parameters.

At runtime, the angular injector inspects that information to determine which dependencies to inject. Specifically, it looks for a registered provider for each corresponding parameter.

Since you haven't registered a provider that maps to the metadata emitted for a parameter of type string the lookup fails and you receive an error. You could register a provider for that type but it would not be wise to do so given just how broadly strings are used.

However, Angular's dependency injection facilities are not limited to this implicit resolution. Using a combination of the Inject decorator and InjectionTokens you can achieve what you wish.

api-token.ts

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

export const apiToken = new InjectionToken('api', {
  providedIn: 'root',
  value: 'myapi'
});

Now you can use this token to request that this dependency is resolved for a specific parameter.

data.service.ts

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

import {apiToken} from './api-token';

@Injectable({providedIn: 'root'})
export class DataService {
   constructor(@Inject(apiToken) api: string) {}
}

Upvotes: 3

Bruno Campos
Bruno Campos

Reputation: 11

i suggest you to remove the api variable from the constructor, pass it on the class methods, use the constructor only to pass injection.


    constructor(public _http: HttpClient) { }

getApi(api: string) {
    this._http.get(api).toPromise()
}

then extends your api service and pass the uri in the parameter, i suggest you let _http public too, the api host cannot see the private http and these typing can fail a build prod

Upvotes: 0

Stanislav Dontsov
Stanislav Dontsov

Reputation: 1741

Angular can't find a provider for api: string. In fact, you do not inject ApiService, you create it in the code here: return new ApiService(item, http, httpUtils), so you don't need to define it in providers.

Upvotes: 0

Related Questions