web-dev-qa-db-fra.com

Comment injecter HttpClient en méthode statique ou en classe personnalisée?

J'aimerais utiliser la forme angulaire HttpClient dans une méthode ou une classe statique (en classe, cela ne peut pas être défini en tant que paramètre constructeur).

J'ai essayé quelque chose comme:

export class SomeNotInjectableService {
  static doSomething() {
    const injector = Injector.create({
      providers: [{provide: HttpClient, deps:[]}]
    });
    const httpClient: HttpClient = injector.get(HttpClient);

    httpClient.request(...); // error Cannot read property 'handle' of undefined
  }
}

il s’agit d’essayer d’injecter manuellement le client dans une méthode de service statique. Ça ne marche pas Je suis curieux de savoir comment faire cela ou comment injecter le client de manière normale mais dans une classe qui n'est pas un composant.

7
elzoy

Je ne suis pas tout à fait sûr que cela ne fonctionne pas comme vous l'avez essayé (il manque probablement quelque chose lorsque vous créez l'injecteur), mais cela fonctionne si vous utilisez un injecteur 'injecté'

Si vous regardez le code renvoyant l'erreur, vous voyez qu'il mentionne les gestionnaires pour la demande, ce qui semble être nul dans votre exemple. Peut-être que angular enregistre certains gestionnaires internes lorsque HttpClient est fourni de manière "traditionnelle", mais pas comme vous le faites

// Commencez avec la requête initiale Observable.of (), puis exécutez le gestionnaire (qui // inclut tous les intercepteurs) à l'intérieur d'un concatMap (). De cette façon, le gestionnaire s'exécute // dans une chaîne observable, ce qui provoque la ré-exécution des intercepteurs à chaque // subscription (cela entraîne également de nouvelles tentatives pour exécuter le gestionnaire, y compris les intercepteurs).

    var /** @type {?} */ events$ = rxjs_operator_concatMap.concatMap.call(rxjs_observable_of.of(req), function (req) { return _this.handler.handle(req); });

Solution de contournement:

app.module.ts

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

export let InjectorInstance: Injector;

export class AppModule 
{
  constructor(private injector: Injector) 
  {
    InjectorInstance = this.injector;
  }
}

Votre classe/méthode statique

import {InjectorInstance} from './app.module';

export class SomeNotInjectableService {
  static doSomething() 
  {
  /*  const injector = Injector.create({
      providers: [{provide: HttpClient, deps:[]}]
    });
    const httpClient: HttpClient = injector.get(HttpClient);
*/
    const httpClient =  InjectorInstance.get<HttpClient>(HttpClient);

    httpClient.request(...)...
  }
}

Exemple sur Stackblitz: https://stackblitz.com/edit/angular-li8b37?file=app%2Fapp.component.ts

9
David

Vous pouvez également ignorer l'injecteur si vous n'en avez pas. Cela signifie que vous devez vous «injecter». Je ne recommande pas cela. Si vous voulez vraiment utiliser une méthode statique (en faveur d'un service approprié), transmettez tous les éléments nécessaires.

Je ne sais pas si cela n'est pas déjà évident, mais aucun intercepteur HTTP manquera dans ce pipeline httpClient, car il n'existe aucun moyen de les résoudre.

import { HttpClient, HttpXhrBackend } from '@angular/common/http';

const httpClient = new HttpClient(new HttpXhrBackend({ build: () => new XMLHttpRequest() }));
httpClient.get('test').subscribe(r => console.log(r));

ou en utilisant votre propre injecteur créé (si vous n'aimez pas passer les arguments de ctor):

const injector = Injector.create({
    providers: [
        { provide: HttpClient, deps: [HttpHandler] },
        { provide: HttpHandler, useValue: new HttpXhrBackend({ build: () => new XMLHttpRequest }) },
    ],
});
const httpClient: HttpClient = injector.get(HttpClient);
httpClient.get('test').subscribe(r => console.log(r));
9
Andrei Tătar

si vous voulez utiliser des intercepteurs dans ce pipeline httpClient, ajoutez deux classes redéfinies à partir des repo angulaires http/src/interceptor.ts et http/src/module.ts:

class HttpInterceptorHandler implements HttpHandler {
  constructor(private next: HttpHandler, private interceptor: HttpInterceptor) {}

  handle(req: HttpRequest<any>): Observable<HttpEvent<any>> {
      return this.interceptor.intercept(req, this.next);
  }
}
class HttpInterceptingHandler implements HttpHandler {
  private chain: HttpHandler|null = null;
  private httpBackend:HttpHandler;
  constructor(private injector: Injector) {
      this.httpBackend = new HttpXhrBackend({ build: () => new XMLHttpRequest });
  }

  handle(req: HttpRequest<any>): Observable<HttpEvent<any>> {
      if (this.chain === null) {
          const interceptors = this.injector.get(HTTP_INTERCEPTORS, []);
          this.chain = interceptors.reduceRight((next, interceptor) => new HttpInterceptorHandler(next,interceptor),this.httpBackend);
      }
      return this.chain.handle(req);
    }
}

Les intercepteurs doivent être dépourvus du décorateur @Injectable:

class HttpIntersept implements HttpInterceptor{
  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
      console.log(req.urlWithParams);
      return next.handle(req)
  }
}

Et comme Andrew était dit

const injector = Injector.create({
providers: [
    { provide: HTTP_INTERCEPTORS, useClass: HttpIntersept, multi: true, deps: []},
    { provide: HTTP_INTERCEPTORS, useClass: HttpIntersept2, multi: true, deps: []},
    { provide: HttpHandler, useClass:HttpInterceptingHandler,deps [Injector,HTTP_INTERCEPTORS]},
    { provide: HttpClient, deps: [HttpHandler] }
 ],
});