Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"Can't resolve all parameters…" with @Optional decorator

I'm getting a strange DI error. This is a piece of auto-generated code from swagger-codegen - I cannot change it. I'm trying to inject this service. However when I run ng build --aot I get the Can't resolve all parameters... DI error.

I tried to remove toe @Optional parameter altogether and it seems to work. So this seems to be the culprit.

My question: Why am I getting an error for not providing the parameter if it is optional? I'm also interested how I would go about if I wanted to actually inject this parameter as it is a primitive type.

@Injectable()
export class MyApi {
    protected basePath = 'https://localhost/';
    public defaultHeaders : Headers = new Headers();

    constructor(protected http: Http, @Optional() basePath: string) {
        if (basePath) {
            this.basePath = basePath;
        }
    }
}

NOTE: The answers of @Nildari and @PierreDuc will probably be what most people may be looking for. However, I'm looking for a solution which won't change the original implementation as it is auto-generated.

like image 540
mode777 Avatar asked Sep 10 '17 06:09

mode777


2 Answers

You need to use an InjectionToken:

export const BASE_PATH: InjectionToken<string> = new InjectionToken<string>('basePath');

// note that the string value `basePath` is just a description of the `InjectionToken` 
// and not actually the base path.

The advantage of using an InjectionToken

Then you need to add an provide object to your providers array of your NgModule:

@NgModule({
    //...
    providers: [
        {provide: BASE_PATH, useValue: '/'}
    ]
})

Then you can inject this provider in your service using @Inject:

constructor(protected http: Http, @Inject(BASE_PATH)basePath: string) {
    if (basePath) {
        this.basePath = basePath;
    }
}

And you can add the @Optional decorator if you feel like it.. but if you add it to your providers array, it will always be found

like image 151
Poul Kruijt Avatar answered Nov 05 '22 06:11

Poul Kruijt


If you want to inject basePath into MyApi service class you can do it like below

Add some 'path' provider to app providers and use @Inject('path') parameter decorator to inject it into MyApi class

@Injectable()
export class MyApi {
    protected basePath = 'https://localhost/';
    public defaultHeaders : Headers = new Headers();

    constructor(protected http: Http, @Inject('path') basePath: string) {
        if (basePath) {
            this.basePath = basePath;
        }
    }
}

Than in the bootstrap file of your application (@NgModule)

bootstrap('name of your app.component class', [
  MyApi, 
  provide('path', { useValue: 'any value which you want to inject'})
]);

you can use @Optional parameter to make the dependency optional.

like image 2
Niladri Avatar answered Nov 05 '22 07:11

Niladri