ps0604
ps0604

Reputation: 1071

HttpClient instance is undefined in Angular 6 service

I have a service that wraps HttpClient. That service is called by a component. The problem is that when I inject the service in the component constructor it is undefined. Moreover, the service constructor seems to not execute at all as a console.log does not print anything. Any ideas?

@Injectable({
  providedIn: 'root'
})
export class MyHttpService {

  constructor(public httpx: HttpClient) {
        console.log("in the constructor - " + this.httpx) // <-- this is never printed
  }

  call () {
        let reqData = { act: 'R'};
        this.httpx.post('/myurl', reqData).subscribe(result => {
            console.log(result);
          }, error => console.log('There was an error: '));
    }
}

The related module is defined as follows:

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { HttpClientModule } from '@angular/common/http';
import { HttpClient } from '@angular/common/http';
import { MyHttpService } from './http.service';

@NgModule({
  imports: [
    CommonModule,
    HttpClientModule, 
    HttpClient
  ],
  declarations: [
    MyHttpService
  ],
  exports: [
    MyHttpService
  ]
})
export class CoreServiceModule {}

The component that calls the service:

@Component({
      selector: 'some-selector',
      templateUrl: 'some-url.html'
    })
export class MyComponent implements OnInit{ 

    constructor(public http:MyHttpService){
          console.log(http);  // <-- this prints undefined
    }

    ngOnInit() {
        let x = this.http.call();  // <-- this fails as http is undefined       
    }


}

And the component module:

@NgModule({
  declarations: [MyComponent],
  exports: [MyComponent],
  imports: [BrowserModule, CoreServiceModule],
  bootstrap: [MyComponent]
})
export class MyModule {}

Upvotes: 1

Views: 7871

Answers (3)

mpontsasa
mpontsasa

Reputation: 21

I had a similar issue:

this.httpx is undefined

For my greatest surprise, changing the function in the service to arrow function solved the problem:

  call = () => {
        let reqData = { act: 'R'};
        this.httpx.post('/myurl', reqData).subscribe(result => {
            console.log(result);
          }, error => console.log('There was an error: '));
    }

Anytime something of this is undefined, first thing I check is if "arrowing" the function helps. More times than what I'm comfortable with, it does. I must assume that this is the doing of the good-old javascript this-fiasco.

Upvotes: 0

Thierry
Thierry

Reputation: 6458

Note that I'm new to Angular, but I've done something similar recently and looking at my own similar project, I've spotted a few differences:

1. When injecting the httpClient, it's a private rather than public

constructor(private http: HttpClient) { }

2. I think you need to include

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

at the top of your MyHttpService module.

3. Note that you've got the same module define twice under a different name:

HttpClientModule, 
HttpClient

I'd remove one to tidiness sake.

Hope this helps.

UPDATE - 1:

This is what I have in my test app. Hopefully, you'll spot something different but it definitely works for me.

app.module.ts:

…
import { HttpClientModule } from '@angular/common/http';
import { HttpService } from './http.service';
…
@NgModule({
  declarations: [
  …
],
imports: [
    …
    HttpClientModule,
    …
  ],
}],
providers: [HttpService],
bootstrap: [AppComponent]
})
export class AppModule { }

I create a separate file for my http client service.

http.service.ts:

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

@Injectable({
  providedIn: 'root'
})

export class HttpService {

  private _loginUrl = "http://...";

  …

  // inject http client in constructor. Make sure it is imported.

  constructor(private http: HttpService) { }

  // Sample function
  loginUser(user) {
    return this.http.post<any>(this._loginUrl, user);
  }
}

and from my view/component:

login.component.ts:

import { HttpService } from '../http.service';

@Component({
  selector: 'app-login',
  templateUrl: './login.component.html',
  styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
  …
  constructor(private _http: HttpService) {
  }

  ngOnInit() {

  }

  loginUser() {
      this._http.loginUser(this.loginUserData).subscribe...
  }
}

Upvotes: 2

Florian
Florian

Reputation: 1481

You should try something like that, do not forget to importe ModuleWithProviders interface from @angular/core.

export class CoreServiceModule {
  static forRoot(): ModuleWithProviders {
    return {
      ngModule: CoreServiceModule,
      providers: [MyHttpService]
    }
  }
}

Note that you need to import this "shared module" in your app.module.ts, and when you declare it in the app.module, you must call forRoot() method. You are then able to use this singleton anywhere in your application without any risk to be re-instanciated.

Upvotes: 1

Related Questions