Подтвердить что ты не робот

Как написать сервис, который требует параметров конструктора?

У меня есть компонент, который объявляет службу 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>
4b9b3361

Ответ 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. Но класс может быть удобно расширен, его легче вводить и уже предоставляет интерфейс для ввода.