1

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 {}
5
  • Shouldn't it be in the providers array ? Commented Jul 20, 2018 at 22:57
  • Your class CoreServiceModule should contain a forRoot() method that returns an object with at least ngModule and providers property. Commented Jul 20, 2018 at 23:01
  • You need not add the service to "exports" & "declaration" arrays, instead, you should add it into the "providers" array. Commented Jul 21, 2018 at 4:17
  • seems like you don't have a basic knowledge of services. Commented Jul 21, 2018 at 4:47
  • 2
    I'm just starting with Angular 6, spent long hours trying to make this work and putting together the question. Also. nobody could give me the answer, so apparently is not that basic. Commented Jul 21, 2018 at 16:15

3 Answers 3

2

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...
  }
}
Sign up to request clarification or add additional context in comments.

8 Comments

Thanks, I didn't post all the imports, I'm already importing HttpClient. I tried with private and public, and get the same error. I also trying importing only the HttpClientModule, but still didn't help.
I've added more details in my answer based on my solution. Maybe this will help.
Note that I've had to edit my additional details a couple of times as I had missed something. One important part I had omitted was the providers. I added it but I've removed details that were required to deal with JWT so I'm not 100% sure whether or not this is how you define a single provider.
The only difference I could see with my code is that you have providers: [MyHttpService], I tried that and didn't work either, sorry :(
My bad, I meant import, BankModule in App module
|
1

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.

4 Comments

Is this native Angular 6? I thought that @NgModule is used only as a decoration
I still get the http undefined, sorry :(
In your ngModule, do you have imports: CoreServiceModule.forRoot() ?
Maybe you could share code with floobits or something ? Angular DI fails to instanciate the service, but I don't see why
1

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.

1 Comment

This actually just worked for me too. I've been chasing an error in a service of mine for hours now and doubt I would have thought to change a method on a class into an arrow func. That's just not my code style. Gotta love javascript.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.