Как написать сервис, который требует параметров конструктора?
У меня есть компонент, который объявляет службу MetricsService
. Для этой службы требуется HttpModule
плюс два string
, которые определяют хост и ключ авторизации для использования.
Служба метрик работает следующим образом:
@Injectable()
export class MetricsService {
constructor(
private http: Http,
public wsAuthKey: string,
public wsHost: string
) {
this.wsAuthKey = wsAuthKey || "blahblahblahblahblahblahblahblah=";
this.wsHost = wsHost || "https://preprod-admin.myservice.ws";
}
Компонент, который его использует, записан следующим образом:
export class DatavizComponent implements OnInit, OnChanges {
constructor(
private zms: MetricsService,
) {
}
Мой вопрос: как мне написать конструктор компонента, чтобы все работало, включая передачу хоста и ключа (но не передачу http)?
Примечание. Код, написанный в данный момент, не компилируется.
Чтобы быть более точным, я ожидаю, что компонент предоставит зависящие от приложения данные примерно так:
export class DatavizComponent implements OnInit, OnChanges {
constructor(
private zms = MetricsService("http://myhost.com", "mykey"),
) {
}
Но если это работает, как передать http?
ОБНОВЛЕНИЕ ПОСЛЕ ПРЕДЛАГАЕМОГО РЕШЕНИЯ:
export class MetricsService {
constructor(
private http: Http,
@Inject('wsAuthKey') @Optional() public wsAuthKey?: string,
@Inject('wsHost') @Optional() public wsHost?: string
) {
this.wsAuthKey = wsAuthKey || "blahblah=";
this.wsHost = wsHost || "https://preprod-admin.host.ws";
console.log("MetricsService constructor="
+ " wsAuthKey="+this.wsAuthKey
+ ", wsHost="+this.wsHost
);
}
В компоненте:
@Component({
selector: 'dataviz-offers-volumes',
templateUrl: 'app/dataviz.component.html',
styleUrls: ['app/dataviz.component.css'],
encapsulation: ViewEncapsulation.None,
providers: [
{provide: 'wsAuthKey', useValue: 'abc'},
{provide: 'wsHost', useValue: 'efg'},
],
})
export class DatavizComponent implements OnInit, OnChanges {
@ViewChild('chart') private chartContainer: ElementRef;
@Input() private graphId:string;
@Input() private wsAuthKey:string;
@Input() private wsHost:string;
@Input() private maxSamples=12;
constructor(
private zms: MetricsService
) {
}
В конструкторе журнал выглядит следующим образом (значения не передаются):
MetricsService constructor= wsAuthKey=blahblah=, wsHost=https://preprod-admin.host.ws
где должно отображаться "abc" и "efg".
Но мне интересно, нет ли проблемы с компонентом, использующим компонент данных dataviz.
В этом компоненте была передана следующая информация:
@Input() private wsAuthKey:string;
@Input() private wsHost:string;
Как я хотел бы, чтобы тег дополнительно настраивал хост и ключ:
<h1>dataviz volume</h1>
<div class="chartContainer left" title="Simultaneous offers via dataviz directive">
<dataviz-offers-volumes
id="dataviz-volumes1"
[graphId]="graphId"
[wsAuthKey]="'myauthkey'"
[wsHost]="'http://myhost.com'"
[maxSamples]="123"
>
</dataviz-offers-volumes>
</div>
Ответы
Ответ 1
Вы можете сделать параметры необязательными, добавив @Optional()
(DI) и ?
(TypeScript) и @Inject(somekey)
для примитивных значений, которые не поддерживаются в качестве ключей поставщика
@Injectable()
export class MetricsService {
constructor(
private http: Http,
@Inject('wsAuthKey') @Optional() public wsAuthKey?: string,
@Inject('wsHost') @Optional() public wsHost?: string
) {
this.wsAuthKey = wsAuthKey || "blahblahblahblahblahblahblahblah=";
this.wsHost = wsHost || "https://preprod-admin.myservice.ws";
}
providers: [
{provide: 'wsAuthKey', useValue: 'abc'},
{provide: 'wsHost', useValue: 'efg'},
]
Если они предоставлены, они передаются, в противном случае они игнорируются, но DI все еще может вводить MetricsService
.
Ответ 2
Это общий рецепт, описанный в этот вопрос в частности. Это должна быть служба, которая содержит конфигурацию:
@Injectable()
export class MetricsConfig {
wsAuthKey = "blahblahblahblahblahblahblahblah=";
wsHost = "https://preprod-admin.myservice.ws";
}
@Injectable()
export class MetricsService {
constructor(
private http: Http,
metricsConfig: MetricsConfig
) {
this.wsAuthKey = metricsConfig.wsAuthKey;
this.wsHost = metricsConfig.wsHost;
}
}
В случае, когда его необходимо изменить, он может быть переопределен или расширен для всего модуля или для конкретного компонента:
@Component(
...
{ provide: MetricsConfig, useClass: class ExtendedMetricsConfig { ... } }
)
export class DatavizComponent ...
В этом случае нет необходимости делать MetricsConfig
класс. Это может быть и поставщик OpaqueToken. Но класс может быть удобно расширен, его легче вводить и уже предоставляет интерфейс для ввода.
Ответ 3
Из официальных документов: https://angular.io/guide/dependency-injection-in-action#injectiontoken
Используйте декоратор @Optional
в конструкторе:
export class MyService {
constructor( @Optional() public var: type = value ) { }
}