25

My constructor has optional parameters and they seem to mess with the predominant way of doing DI.

constructor(public name:string, public age?:number, private _service:Service);

Typescript understandably doesn't like that I put a non optional parameter behind an optional one, furthermore the service doesn't get injected when the optional parameter isn't set. How do I solve that? I can't put it somewhere else in the constructor since I would be expected setting the service manually.

Is there something like field injection?

@Inject() private _service:Service;

constructor(public name:string, public age?:number);

Should I replace the optional parameters with default values? Any other suggestions?

EDIT: As discussed below, I tried to inject a service into an object that isn't created by Angular's DI. This doesn't work. Since I can't create this class (model) using DI I now pass the service manually from the class that instantiates this objects.

2 Answers 2

37

Just add the @Optional() decorator before the constructor parameter that should only be injected if there was a provider registered.

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

constructor(public name:string, @Optional() public age:number)
Sign up to request clarification or add additional context in comments.

11 Comments

I may be missing something, but "age" is not the thing I want to be injected. I create new object using the constructor like new Person("Mike", 32); and the Service should get injected independent from setting the age or not. Or do I just need to annotate every optional (TS=?) with @Optional()?
Not sure I fully understand your question. With new Person("Mike", 32) there is no dependency injection involved at all. DI is only involved when instances are created by DI itself. For example components and its dependencies are instantiated by DI. Can you please clarify?
"DI is only involved when instances are created by DI itself." I guess that's my "problem" or thing I didn't understand. I create the objects manually setting name and age using the constructor. I thought the DI would inject the other parameters with a registered provider. Guess that doesn't work.
The Person class isn't injectable, therefore I this ins't an option. Person is just a model class with a save function that needs a service - which I would've liked to inject. I guess I need to restructure the class or get the service another way.
if you get private _service:Service injected to the component where you want to create a new Person() then you can just do new Person("Mike", 32, this._service) (still not sure if this is where you want to pass the service to though).
|
6

If I understand correctly what you are trying to do, you need a service factory. See here: https://angular.io/docs/ts/latest/guide/dependency-injection.html#factory-provider

Basically,

class MyClass {
    constructor(public name:string, private _service:Service, public age?:number){}
}

And then

let myFactory = (_service: Service) => {
  return isAgeOk ? new MyClass(name, _service, age) : new MyClass(name, _service);
};

And then you should provide your service like this:

providers: [{ provide: MyClass, useFactory: MyFactory, deps: [Service]}]

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.