web-dev-qa-db-fra.com

Comment écrire un constructeur de service nécessitant des paramètres dans angular 2?

J'ai un composant qui déclare le service MetricsService. Ce service nécessite à la fois le module http et deux chaînes définissant l'hôte et la clé d'authentification à utiliser.

Le service de métriques est le suivant:

@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";
    }

Le composant qui l'utilise est écrit comme suit:

export class DatavizComponent implements OnInit, OnChanges {
    constructor(
        private zms: MetricsService,
    ) { 
    }

Ma question est la suivante: comment devrais-je écrire le constructeur du composant pour que tout fonctionne, y compris en transmettant l'hôte et la clé (sans transmettre le http)?

Remarque: le code tel qu'il est écrit actuellement ne compile pas.

Pour être plus précis, je m'attendrais à ce que le composant fournisse des données dépendantes de l'application, par exemple:

 export class DatavizComponent implements OnInit, OnChanges {
        constructor(
            private zms = MetricsService("http://myhost.com", "mykey"),
        ) { 
        }

Mais si cela fonctionne, comment passer http?

MISE À JOUR APRÈS LA SOLUTION PROPOSÉE:

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
        );

    }

Dans le composant:

@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
    ) { 
    }

Dans le constructeur, le journal est le suivant (les valeurs ne sont pas transmises):

MetricsService constructor= wsAuthKey=blahblah=, wsHost=https://preprod-admin.Host.ws

où il devrait montrer 'abc' et 'efg'.

Mais je me demande s’il n’ya pas de problème avec le composant qui utilise dataviz composant .. >>. Dans ce composant, les informations suivantes ont été transmises:

@Input() private wsAuthKey:string;
@Input() private wsHost:string;

Comme je voudrais que la balise prédéfinisse l’hôte et la clé:

                <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>
17
Stéphane de Luca

Vous pouvez rendre les paramètres facultatifs en ajoutant @Optional() (DI) et ? (TypeScript), et @Inject(somekey) pour les valeurs primitives non prises en charge en tant que clés de fournisseur.

@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'}, 
]

S'ils sont fournis, ils sont validés, sinon ils sont ignorés, mais l'ID peut toujours injecter la variable MetricsService.

24
Günter Zöchbauer

Ceci est une recette courante décrite dans cette question en particulier. Ce devrait être un service qui contient la configuration:

@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;
    }
}

Dans le cas où il doit être modifié, il peut être remplacé ou étendu pour tout le module ou pour un composant particulier:

@Component(
  ...
  { provide: MetricsConfig, useClass: class ExtendedMetricsConfig { ... } }
)
export class DatavizComponent ...

Il n'est pas vraiment nécessaire de faire MetricsConfig une classe dans ce cas. Il peut également s'agir d'un fournisseur de valeur OpaqueToken. Mais une classe peut être étendue, il est plus facile à injecter et fournit déjà une interface pour la frappe.

10
estus

D'après les documents officiels: https://angular.io/guide/dependency-injection-in-action#injectiontoken

Utilisez un décorateur @Optional dans le constructeur:

export class MyService {
  constructor( @Optional() public var: type = value ) { }
}
0
Gus