javascriptangularrest

Angular 17 Http client injection


I am building a new app for testing with angular 17 trying to connect to a simple API rest. I am desperate to get this to work. I have asked chat GPT, reviewed stack's older posts and even download an old application, but with no success.

Here is my app config and the error:

app.module.ts

import {FormsModule, ReactiveFormsModule} from '@angular/forms';
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import {AppComponent} from "./app.component";
import {HttpClientModule} from "@angular/common/http";
import {ClienteService} from "./cliente.service";
import {ClienteComponent} from "./cliente/cliente.component";
import {AppRoutingModule} from "./app-routing.module";



@NgModule({
  declarations: [
    AppComponent,
    ClienteComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    ReactiveFormsModule,
    HttpClientModule,
    AppRoutingModule

  ],
  providers: [ClienteService],
  bootstrap: [AppComponent]
})
export class AppModule { }

app-routing.module.ts


import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';

import {ClienteComponent} from "./cliente/cliente.component";

const appRoutes: Routes = [
  { path: '', redirectTo: '/clientes', pathMatch: 'full' },
  { path: 'clientes', component: ClienteComponent}
];

@NgModule({
  imports: [RouterModule.forRoot(appRoutes)],
  exports: [RouterModule]
})
export class AppRoutingModule {

}

cliente.service.ts

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

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

  private clienteUrl: string;

  constructor(private http: HttpClient) {
    this.clienteUrl = 'http://localhost:8081/clientes';
  }
  getClientes(nombre?: string, telefono?: string, direccion?: string) {
    const params: any = { nombre, telefono, direccion };
    return this.http.get(this.clienteUrl, { params });
  }

cliente.component.ts

import {Component, OnInit} from '@angular/core';
import { CommonModule } from '@angular/common';
import {ClienteService} from "../cliente.service";

@Component({
  selector: 'app-cliente',
  standalone: true,
  imports: [CommonModule],
  templateUrl: './cliente.component.html',
  styleUrl: './cliente.component.css'
})
export class ClienteComponent implements OnInit{

  clientes: any[] = [];

  constructor(private clienteService: ClienteService) {

  }

  ngOnInit(): void {
    this.clienteService.getClientes().subscribe((clientesResponse:any) => {
      console.log('Respuesta del servicio getAllClientes',clientesResponse);
      this.clientes=clientesResponse._embedded.clientes;


    });
  }

}

The problem is this:

ERROR NullInjectorError: R3InjectorError(Standalone[_AppComponent])[_ClienteService -> _ClienteService -> _HttpClient -> _HttpClient]: 
  NullInjectorError: No provider for _HttpClient!
    at NullInjector.get (core.mjs:5601:27)
    at R3Injector.get (core.mjs:6044:33)
    at R3Injector.get (core.mjs:6044:33)
    at injectInjectorOnly (core.mjs:911:40)
    at Module.ɵɵinject (core.mjs:917:42)
    at Object.ClienteService_Factory [as factory] (cliente.service.ts:7:28)
    at core.mjs:6164:43
    at runInInjectorProfilerContext (core.mjs:867:9)
    at R3Injector.hydrate (core.mjs:6163:17)
    at R3Injector.get (core.mjs:6033:33)
handleError @ core.mjs:11747

Solution

  • You are mixing Modules and Standalone Components. As of Angular 17 everything is standalone by default, unless you specify otherwise.

    You have 2 options.

    1. Don't use stand alone components, make your components part of modules, then the import arrays in the modules should work.
    2. Work without modules and make the app completely standalone. As intended from Angular 17

    If you started a project in angular 17, I suggest against option number one.

    For start, go to main.js and add provideHttpClient(withFetch()) to the providers array. Insted of importing HttpClientModule in your AppModule.

    bootstrapApplication(AppComponent, {
      providers: [
        provideHttpClient(withFetch()),
      ],
    });
    

    Further Explanation

    The new implementation for Angular 17 might seem obscure compared to the previous versions, so here's a bit more detail.

    Standalone Components vs. Traditional Modules

    Standalone Components:

    Traditional Modules:

    Implementing Standalone Components

    ng generate component my-component --standalone
    
    import { bootstrapApplication } from '@angular/platform-browser';
    import { AppComponent } from './app/app.component';
    import { provideHttpClient, withFetch } from '@angular/common/http';
    
    bootstrapApplication(AppComponent, {
      providers: [
        provideHttpClient(withFetch()), // Configure the HttpClient here
        // Add the rest of the providers here
      ],
    });
    

    Benefits of the Standalone Approach