web-dev-qa-db-fra.com

Aucun fournisseur pour ConnectionBackend lors de l'héritage de Http

J'essaie de créer un wrapper autour du service HTTP intégré dans angular 2 pour pouvoir ajouter un comportement personnalisé (en-têtes, paramètres, etc.)

J'ai donc créé une classe habituelle (pas un service) et l'ai héritée de Http. Définition de classe

import {
  Http,
  ConnectionBackend,
  RequestOptions,
  RequestOptionsArgs,
  Headers
} from '@angular/http';
import { Observable } from 'rxjs/Observable';
import {tamamApiUrl} from '../constants';
import {CustomQueryEncoder} from './CustomQueryEncoder';
import 'rxjs/Rx';

export class BaseHttp extends Http {
  protected applicationDataService;
  protected baseUrl: string = tamamApiUrl;
  protected encoder: CustomQueryEncoder;

  constructor(backend:ConnectionBackend,
              defaultOptions: RequestOptions, applicationDataService: any) {
    super(backend, defaultOptions);
    this.applicationDataService = applicationDataService;
  }


  get(url: string, options?: RequestOptionsArgs): Observable<any> {
    this.addDefaultOptions(options);
    return super.get(url, options);
  }

  post(url: string, body: any, options?: RequestOptionsArgs): Observable<any> {
    this.addDefaultOptions(options);
    this.addDefaultPostOptions(options);
    return super.post(url, body, options);
  }

  private addDefaultOptions(options?: RequestOptionsArgs): RequestOptionsArgs {
    if (options == null) {
      options = new RequestOptions();
    }
    if (options.headers == null) {
      options.headers = new Headers();
    }
    const applicationData = this.applicationDataService.getApplicationData();

    if (applicationData.applicationKey) {
      options.headers.append('application-id', applicationData.applicationKey);
    }

    if (applicationData.secretKey) {
      options.headers.append('secret-key', applicationData.secretKey);
    }

    if (applicationData.userToken) {
      options.headers.append('user-token', applicationData.userToken);
    }

    return options;
  }

  private addDefaultPostOptions(options): void {
    options.headers.append('Content-Type', 'application/json');
  }

  /*private requestInterceptor(): void {
    this.loaderService.showPreloader();
  }


  private responseInterceptor(): void {
    this.loaderService.hidePreloader();
  }*/
}

Than I a créé un service qui a hérité de cette classe afin que je puisse l'injecter plus tard et l'utiliser à mes fins. 

import { Headers, URLSearchParams } from '@angular/http';
import {tamamRootUrl} from '../constants';
import {BaseHttp} from '../api/BaseHttp';
import { Injectable } from '@angular/core';
import {
  ConnectionBackend,
  RequestOptions,
} from '@angular/http';
import {ApplicationService} from './ApplicationService';

@Injectable()
export class InspectionHttpService extends BaseHttp{

  protected baseUrl: string = tamamRootUrl;
  protected params: URLSearchParams = new URLSearchParams();

  constructor(backend: ConnectionBackend,
              defaultOptions: RequestOptions, protected applicationService: ApplicationService) {
    super(backend, defaultOptions, applicationService);
  }

  getRootUrl() {
    return this.baseUrl;
  }
}

Définition du service

Après avoir essayé d'injecter le service créé dans le composant, un message d'erreur s'affiche:

error_handler.js: 47 EXCEPTION: Uncaught (promis): Erreur: Erreur dans la classe ./VehiclesListComponent VehiclesListComponent_Host - modèle en ligne: 0: 0 provoqué par: Aucun fournisseur pour ConnectionBackend!

J'ai essayé de chercher une solution en utilisant un débordement de pile, mais il s'est avéré que HtpModule devrait déjà avoir tout le nécessaire pour un travail correct.

Quelqu'un pourrait-il m'aider? Où est le problème?

12
Nick Shulzhenko

Vous ne pouvez pas simplement l'ajouter aux fournisseurs comme ceci

providers: [ ApplicationService, InspectionHttpService ]

Si vous le faites, alors Angular essaiera de le créer, mais il ne trouvera pas de fournisseur pour ConnectionBackend

Vous devez utiliser une fabrique, où vous pouvez simplement passer la XHRBackend (qui implémente ConnectionBackend)

imports: [HttpModule],
providers: [
  ApplicationService,
  {
    provide: InspectionHttpService,
    deps: [XHRBackend, RequestOptions, ApplicationService],
    useFactory: (backend, options, aplicationService) => {
      return new InspectionHttpService(backend, options, applicationService);
    }
  }
]

Avec cela, vous pouvez l’injecter sous la forme InspectionHttpService.

constructor(private http: InspectionHttpService) {}

Si vous voulez pouvoir l’injecter sous la forme Http, vous devez changer le provide en Http au lieu de InspectionHttpService. Mais cela annule toute possibilité d'utiliser la constante Http si vous en avez besoin.

METTRE À JOUR

Dans certains environnements, il est possible que vous obteniez une erreur avec le code ci-dessus. J'ai oublié le message d'erreur exact, mais cela vous donnera une solution d'extraction de la fonction factory, c'est-à-dire.

export function httpFactory(backend: XHRBackend, options: RequestOptions,
                            service: ApplicationService) {
  return new InspectionHttpService(backend, options, service);
}

useFactory: httpFactory

D'après mes souvenirs, je pense que l'erreur a quelque chose à voir avec AoT

15
Paul Samsotha

Lors de l'extension du service HTTP, vous devez injecter le backend et les options pour la classe parente:

@Injectable()
export class HttpInterceptor extends Http {
  constructor(
    backend: XHRBackend,
    options: RequestOptions,
    ...
  ) {
    super(backend, options);
  }
  ...
}

De cette façon, vous n’aurez pas à utiliser une usine car Angular calculera l’injection elle-même.

0
gabo bernal