Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

No provider for ConnectionBackend while inheriting from Http

I am trying to make a wrapper around built in Http service in angular 2 to have a possibility to add custom behaviour (headers, parameters etc.)

So I created a usual class (not a service) and inherit it from Http. Class definition

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 Created a service which inherited from this class so that I can inject it later and use for my purposes.

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

Service definition

After I try to inject created service in component I receive an error:

error_handler.js:47 EXCEPTION: Uncaught (in promise): Error: Error in ./VehiclesListComponent class VehiclesListComponent_Host - inline template:0:0 caused by: No provider for ConnectionBackend!

I tried to search solution using stack-overflow but it see,s that HtpModule should already have all necessary for a proper work.

Could anyone help me? Where is the problem?

like image 589
Nick Shulzhenko Avatar asked Nov 09 '16 13:11

Nick Shulzhenko


1 Answers

You can't just add it to the providers like this

providers: [ ApplicationService, InspectionHttpService ]

If you do, then Angular will try to create it, and it won't find a provider for ConnectionBackend

You need to use a factory, where you can just pass the XHRBackend (which implements ConnectionBackend)

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

With this, you can inject it as InspectionHttpService.

constructor(private http: InspectionHttpService) {}

If you want to be able to inject it as Http, then you need to change the provide to Http instead of InspectionHttpService. But this overrides any ability to use the regular Http if you ever need it.

UPDATE

In some environments, it's possible you may get an error with the above code. I forgot the exact error message, but it will give you a proposed solution of extracting the factory function, i.e.

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

useFactory: httpFactory

From what I remember, I think the error has something to do with AoT

like image 61
Paul Samsotha Avatar answered Nov 03 '22 09:11

Paul Samsotha