Injected dependency is undefined when extending Ba

2019-02-27 12:22发布

I am extending BaseRequestOptions in Angular2 to add headers for each request. I also have a Config class that supplies key/value pairs based on the domain, which I need to inject into my derived class:

import { BaseRequestOptions } from '@angular/http';
import { Config } from '../../config/configuration';

export class DefaultRequestOptions extends BaseRequestOptions {
  constructor(private config: Config) {
    super();

    Object.keys(this.config.api.headers).map((key) => {
      this.headers.append(key, this.config.api.headers[key]);
    });
  }
}

In my module, I am specifying the provider as such:

@NgModule({
  . . .,
  providers: [
    . . .,
    { provide: RequestOptions, useClass: DefaultRequestOptions }
  ]
})
. . .

The problem I'm having is that this.config is undefined in DefaultRequestOptions. I am also using the Config class as an injected dependency in other classes, so I'm confident it's working as expected, and if I manually set the values for this.headers everything works fine.

What am I doing wrong that would cause the config to be undefined in DefaultRequestOptions?

2条回答
贼婆χ
2楼-- · 2019-02-27 12:42

This is actually much easier than peeskillet's answer. When defining your provider also specify the dependencies for that provider so it would look like:

providers: [
{
    provide: RequestOptions,
    useClass: DefaultRequestOptions,
    deps: [Config]
};
查看更多
SAY GOODBYE
3楼-- · 2019-02-27 12:43

Provider classes don't require @Injectable() unless they require constructor parameters to be injected. In your case it does. This is why Angular recommends to always use it on your providers, whether or not you require injections. Maybe for this exact reason, where you forget, when it's needed.

@Injectable()
export class DefaultRequestOptions extends BaseRequestOptions {

After testing

It seems this still doesn't work. I've seen this problem is a result of extending a class that already uses @Injectable() (which BaseRequestOptions does). In this case, the parent constructor is called instead of the extending class'. If you extend RequestOptions instead (which is not decorated with @Injectable()) then it would work

@Injectable()
class DefaultRequestOptions extends RequestOptions {
  constructor(public config: Config) {
    super({method: RequestMethod.Get, headers: new Headers()})

    this.headers.append('data', this.config.data);
  }
}

Notice the super() call. This is all that BaseRequestOptions does.

If you wanted to keep it the way it currently is, using BaseRequestOptions, then you could use a factory, instead of letting Angular create it

{
  provide: RequestOptions,
  deps: [ Config ],
  useFactory: (config: Config) => {
    return new DefaultRequestOptions(config);
  }
}
查看更多
登录 后发表回答