hholtij
hholtij

Reputation: 2936

Inject Http manually in Angular 4

I want to manually bootstrap an Angular 4 app (created with CLI). In main.ts I am doing this:

const injector = ReflectiveInjector.resolveAndCreate([
  Http,
  BrowserXhr,
  {provide: RequestOptions, useClass: BaseRequestOptions},
  {provide: ResponseOptions, useClass: BaseResponseOptions},
  {provide: ConnectionBackend, useClass: XHRBackend},
  {provide: XSRFStrategy, useFactory: () => new CookieXSRFStrategy()},
]);
const http = injector.get(Http);

http.get('assets/configs/configuration.json')
  .map((res: Response) => {
    return res.json();
  }).subscribe((config: Configuration) => {
  configuration = config;
  console.log(JSON.stringify(configuration));
  platformBrowserDynamic().bootstrapModule(AppModule);
});

I seem to get a valid Http instance but when I use it (http.get) I get this error:

Uncaught TypeError: Cannot read property 'getCookie' of null
    at CookieXSRFStrategy.webpackJsonp.../../../http/@angular/http.es5.js.CookieXSRFStrategy.configureRequest (vendor.bundle.js:141626)

My http object looks like this: enter image description here

Upvotes: 2

Views: 4615

Answers (4)

Jens Bodal
Jens Bodal

Reputation: 1757

Possibly the original answer worked before, but in Angular 5 I was not able to use it, there was no definition for the function getAnnotations. This is what did work for me however:

import { ReflectiveInjector } from '@angular/core';
import {
  HttpClient,
  XhrFactory,
  HttpHandler,
  HttpXhrBackend,
  HttpBackend
} from '@angular/common/http';

// https://github.com/angular/angular/blob/master/packages/common/http/src/xhr.ts#L45
export class BrowserXhr implements XhrFactory {
  build(): any { return <any>(new XMLHttpRequest()); }
}

const injector = ReflectiveInjector.resolveAndCreate([
  HttpClient,
  HttpXhrBackend,
  { provide: HttpBackend, useExisting: HttpXhrBackend },
  { provide: HttpHandler, useExisting: HttpBackend },
  { provide: XhrFactory, useClass: BrowserXhr},
]);

const http: HttpClient = injector.get(HttpClient);

http.get('/url').subscribe((response) => {
  console.log(response);
});

Upvotes: 2

Max Koretskyi
Max Koretskyi

Reputation: 105517

You can use HttpClient service before the Angular starts using ReflectiveInjector like this:

import { ReflectiveInjector } from '@angular/core';
import { HttpClient, HttpClientModule } from '@angular/common/http';
const injector = ReflectiveInjector.resolveAndCreate(getAnnotations(HttpClientModule)[0].providers);

const http = injector.get(HttpClient);
http.get('/posts/1').subscribe((r) => {
  ConfigurationService.configuration = <Configuration>JSON.parse(config);
  platformBrowserDynamic().bootstrapModule(AppModule);
});

This line:

getAnnotations(HttpClientModule).providers

references all providers that are registered on the HttpClientModule so you don't have to specify them manually. This answer explains the getAnnotations function in great details.

The approach I've shown is "sort of" the similar to what you're doing when importing HttpClientModule into the AppModule:

@NgModule({
    imports: [HttpClientModule, ...],
})
export class AppModule {}

See this plunker for details.

Upvotes: 6

angularconsulting.au
angularconsulting.au

Reputation: 28309

As another approach you can use the native browser fetch api. So you do not have to deal with angular http, etc

That is how I am doing that:

fetch(configUrl, { method: 'get' })
.then((response) => {
  response.json()
    .then((data: any) => {
      if (environment.production) {
        enableProdMode();
      };
      platformBrowserDynamic([{ provide: AppSettings, useValue: new AppSettings(data.config) }]).bootstrapModule(AppModule);
    });
});

But bare in mind that fetch didn't get much love in old browsers so you need to polyfil that with whatwg-fetch like npm install whatwg-fetch --save then import 'whatwg-fetch' in polyfills.ts in order if you want to support old browsers.

UPDATE: Yeah you can use XMLHttpRequest but you are getting same browsers support with that as fetch just a modern replacement for XMLHttpRequest.

Upvotes: 5

hholtij
hholtij

Reputation: 2936

Thanks, Kuncevic. I have come up with this solution, which works fine:

function httpGetAsync(theUrl, callback) {
  const xmlHttp = new XMLHttpRequest();

  xmlHttp.onreadystatechange = function() {
    if (xmlHttp.readyState === 4 && xmlHttp.status === 200) {
      callback(xmlHttp.responseText);
    }
  }

  xmlHttp.open('GET', theUrl, true); // true for asynchronous
  xmlHttp.send(null);
}

httpGetAsync('assets/configs/configuration.json', (config: string) => {
  ConfigurationService.configuration = <Configuration>JSON.parse(config);
  platformBrowserDynamic().bootstrapModule(AppModule);
});

Upvotes: 1

Related Questions