I am working on an Angular standalone application and I am getting the following error when trying to use HttpClient in my service: ERROR Error: NullInjectorError: R3InjectorError(Standalone[_PatientsComponent])[_PatientsService -> _HttpClient -> HttpHandler -> HttpHandler]: NullInjectorError: No provider for HttpHandler! **I am using Angular CLI: 18.2.12
I am using provideHttpClient() in main.ts when bootstrapping the application. My PatientsService is using inject(HttpClient), which should work in a standalone environment. I have also tried adding provideHttpClient() in my patientsponent.ts under providers, but the error still persists.
main.ts:
import { enableProdMode } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app/appponent';
import { environment } from './environments/environment';
import { provideRouter } from '@angular/router';
import { routes } from './app/app.routes';
import {provideHttpClient} from '@angular/common/http';
if (environment.production) {
enableProdMode();
}
console.log('Initializing Angular app with provideHttpClient');
bootstrapApplication(AppComponent, {
providers: [
provideRouter(routes), // Configurează rutarea
provideHttpClient(),
],
}).catch(err => console.error(err));
app.config.ts:
import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';
import { provideRouter } from '@angular/router';
import { routes } from './app.routes';
import { provideClientHydration } from '@angular/platform-browser';
export const appConfig: ApplicationConfig = {
providers: [provideZoneChangeDetection({ eventCoalescing: true }), provideRouter(routes), provideClientHydration()]
};
patientponent.ts:
import {Component, inject, OnInit} from '@angular/core';
import {FormBuilder, FormGroup, ReactiveFormsModule, Validators} from '@angular/forms';
import { PatientsService } from '../../services/patients.service';
import { catchError, Observable, throwError } from 'rxjs';
import { PageRespone } from '../../model/page.response.model';
import { Patient } from '../../model/patient.model';
import {AsyncPipe, NgClass, NgForOf, NgIf} from '@angular/common';
import {NgbModal} from '@ng-bootstrap/ng-bootstrap';
import {AppointmentsService} from '../../services/appointments.service';
import {Appointment} from '../../model/appointment.model';
@Component({
selector: 'app-patients',
standalone: true,
templateUrl: './patientsponent.html',
imports: [
ReactiveFormsModule,
NgIf,
AsyncPipe,
NgForOf,
NgClass
],
styleUrl: './patientsponent.scss'
})
export class PatientsComponent implements OnInit {
searchFormGroup!: FormGroup;
modalPatient!:Patient;
currentPage: number = 0;
pageSize: number = 5;
errorMessage!: string;
pagePatients!: Observable<PageRespone<Patient>>;
submitted : boolean = false;
patientFormGroup !: FormGroup;
updatePatientFormGroup!: FormGroup;
appointmentCurrentPage: number =0;
pageAppointment$!:Observable<PageRespone<Appointment>>;
appointmentPageSize: number =5;
appointmentErrorMessage!:string;
private patientsService = inject(PatientsService); // Injectare Lazy
private appointmentService = inject(AppointmentsService);
constructor(
private modalService : NgbModal,
private fb: FormBuilder
) {}
ngOnInit(): void {
this.searchFormGroup = this.fb.group({
keyword: this.fb.control('')
});
this.patientFormGroup = this.fb.group({
firstName:["", Validators.required],
lastName:["", Validators.required],
medicalHistory: [[]],
allergies: [[]],
user: this.fb.group({
email: ['', [Validators.required, Validators.email]],
password: ['', [Validators.required, Validators.minLength(6)]]
})
});
this.handleSearchPatients(); // Load patients on init
}
// Deschide modalul
openModal(content:any){
this.submitted=false;
this.modalService.open(content, {size : 'xl'})
}
onCloseModal(modal: any) {
modal.close();
this.patientFormGroup.reset();
}
handleSearchPatients() {
let keyword = this.searchFormGroup.value.keyword;
this.pagePatients = this.patientsService.searchPatients(keyword, this.currentPage, this.pageSize).pipe(
catchError(err => {
console.error("Error fetching patients:", err);
this.errorMessage = "Failed to load patients!";
return throwError(err);
})
);
}
gotoPage(page: number) {
this.currentPage = page;
this.handleSearchPatients();
}
patinet.service.ts:
import {inject, Injectable} from '@angular/core';
import {HttpClient, HttpHeaders} from '@angular/common/http';
import {Observable} from 'rxjs';
import {Patient} from '../model/patient.model';
import {environment} from '../../environments/environment';
import {PageRespone} from '../model/page.response.model';
import {Appointment} from '../model/appointment.model';
@Injectable({
providedIn: 'root'
})
export class PatientsService {
//Funcționează perfect în standalone: true, fără a fi nevoie să declari explicit providerii în fiecare componentă.
// Nu este afectată de ordinea de inițializare, deoarece injectarea se face doar când este necesară.
// Este mai flexibilă și permite folosirea serviciilor în afara constructorului (ex: în variabile statice sau în funcții).
private http = inject(HttpClient);
constructor() {
console.log('PatientsService initialized!');
console.trace('PatientsService stack trace');
}
public searchPatients(keyword: string, currentPage: number, pageSize: number): Observable<PageRespone<Patient>> {
return this.http.get<PageRespone<Patient>>(
`${environment.backendHost}/patients?keyword=${keyword}&page=${currentPage}&size=${pageSize}`
);
}
public findAllPatients() : Observable<Array<Patient>>{
return this.http.get<Array<Patient>>(environment.backendHost + "/patients/all")
}
public deletePatient(patientId: number) {
return this.http.delete<void>(environment.backendHost + "/patients/" + patientId);
}
public savePatient(patient: Partial<Patient>): Observable<any> {
return this.http.post<Patient>(environment.backendHost + "/patients", patient, {
headers: new HttpHeaders({ "Content-Type": "application/json" })
});
}
updatePatient(patient: Patient, id: number): Observable<any> {
return this.http.put<Patient>(`${environment.backendHost}/patients/${id}`, patient, {
headers: new HttpHeaders({ "Content-Type": "application/json" })
});
}
public getNoAppointmentsByPatientId(patientId: number, page: number, size: number): Observable<PageRespone<Appointment>> {
return this.http.get<PageRespone<Appointment>>(
`${environment.backendHost}/patients/${patientId}/other-appointments?page=${page}&size=${size}`
);
}
}
I am working on an Angular standalone application and I am getting the following error when trying to use HttpClient in my service: ERROR Error: NullInjectorError: R3InjectorError(Standalone[_PatientsComponent])[_PatientsService -> _HttpClient -> HttpHandler -> HttpHandler]: NullInjectorError: No provider for HttpHandler! **I am using Angular CLI: 18.2.12
I am using provideHttpClient() in main.ts when bootstrapping the application. My PatientsService is using inject(HttpClient), which should work in a standalone environment. I have also tried adding provideHttpClient() in my patientsponent.ts under providers, but the error still persists.
main.ts:
import { enableProdMode } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app/appponent';
import { environment } from './environments/environment';
import { provideRouter } from '@angular/router';
import { routes } from './app/app.routes';
import {provideHttpClient} from '@angular/common/http';
if (environment.production) {
enableProdMode();
}
console.log('Initializing Angular app with provideHttpClient');
bootstrapApplication(AppComponent, {
providers: [
provideRouter(routes), // Configurează rutarea
provideHttpClient(),
],
}).catch(err => console.error(err));
app.config.ts:
import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';
import { provideRouter } from '@angular/router';
import { routes } from './app.routes';
import { provideClientHydration } from '@angular/platform-browser';
export const appConfig: ApplicationConfig = {
providers: [provideZoneChangeDetection({ eventCoalescing: true }), provideRouter(routes), provideClientHydration()]
};
patientponent.ts:
import {Component, inject, OnInit} from '@angular/core';
import {FormBuilder, FormGroup, ReactiveFormsModule, Validators} from '@angular/forms';
import { PatientsService } from '../../services/patients.service';
import { catchError, Observable, throwError } from 'rxjs';
import { PageRespone } from '../../model/page.response.model';
import { Patient } from '../../model/patient.model';
import {AsyncPipe, NgClass, NgForOf, NgIf} from '@angular/common';
import {NgbModal} from '@ng-bootstrap/ng-bootstrap';
import {AppointmentsService} from '../../services/appointments.service';
import {Appointment} from '../../model/appointment.model';
@Component({
selector: 'app-patients',
standalone: true,
templateUrl: './patientsponent.html',
imports: [
ReactiveFormsModule,
NgIf,
AsyncPipe,
NgForOf,
NgClass
],
styleUrl: './patientsponent.scss'
})
export class PatientsComponent implements OnInit {
searchFormGroup!: FormGroup;
modalPatient!:Patient;
currentPage: number = 0;
pageSize: number = 5;
errorMessage!: string;
pagePatients!: Observable<PageRespone<Patient>>;
submitted : boolean = false;
patientFormGroup !: FormGroup;
updatePatientFormGroup!: FormGroup;
appointmentCurrentPage: number =0;
pageAppointment$!:Observable<PageRespone<Appointment>>;
appointmentPageSize: number =5;
appointmentErrorMessage!:string;
private patientsService = inject(PatientsService); // Injectare Lazy
private appointmentService = inject(AppointmentsService);
constructor(
private modalService : NgbModal,
private fb: FormBuilder
) {}
ngOnInit(): void {
this.searchFormGroup = this.fb.group({
keyword: this.fb.control('')
});
this.patientFormGroup = this.fb.group({
firstName:["", Validators.required],
lastName:["", Validators.required],
medicalHistory: [[]],
allergies: [[]],
user: this.fb.group({
email: ['', [Validators.required, Validators.email]],
password: ['', [Validators.required, Validators.minLength(6)]]
})
});
this.handleSearchPatients(); // Load patients on init
}
// Deschide modalul
openModal(content:any){
this.submitted=false;
this.modalService.open(content, {size : 'xl'})
}
onCloseModal(modal: any) {
modal.close();
this.patientFormGroup.reset();
}
handleSearchPatients() {
let keyword = this.searchFormGroup.value.keyword;
this.pagePatients = this.patientsService.searchPatients(keyword, this.currentPage, this.pageSize).pipe(
catchError(err => {
console.error("Error fetching patients:", err);
this.errorMessage = "Failed to load patients!";
return throwError(err);
})
);
}
gotoPage(page: number) {
this.currentPage = page;
this.handleSearchPatients();
}
patinet.service.ts:
import {inject, Injectable} from '@angular/core';
import {HttpClient, HttpHeaders} from '@angular/common/http';
import {Observable} from 'rxjs';
import {Patient} from '../model/patient.model';
import {environment} from '../../environments/environment';
import {PageRespone} from '../model/page.response.model';
import {Appointment} from '../model/appointment.model';
@Injectable({
providedIn: 'root'
})
export class PatientsService {
//Funcționează perfect în standalone: true, fără a fi nevoie să declari explicit providerii în fiecare componentă.
// Nu este afectată de ordinea de inițializare, deoarece injectarea se face doar când este necesară.
// Este mai flexibilă și permite folosirea serviciilor în afara constructorului (ex: în variabile statice sau în funcții).
private http = inject(HttpClient);
constructor() {
console.log('PatientsService initialized!');
console.trace('PatientsService stack trace');
}
public searchPatients(keyword: string, currentPage: number, pageSize: number): Observable<PageRespone<Patient>> {
return this.http.get<PageRespone<Patient>>(
`${environment.backendHost}/patients?keyword=${keyword}&page=${currentPage}&size=${pageSize}`
);
}
public findAllPatients() : Observable<Array<Patient>>{
return this.http.get<Array<Patient>>(environment.backendHost + "/patients/all")
}
public deletePatient(patientId: number) {
return this.http.delete<void>(environment.backendHost + "/patients/" + patientId);
}
public savePatient(patient: Partial<Patient>): Observable<any> {
return this.http.post<Patient>(environment.backendHost + "/patients", patient, {
headers: new HttpHeaders({ "Content-Type": "application/json" })
});
}
updatePatient(patient: Patient, id: number): Observable<any> {
return this.http.put<Patient>(`${environment.backendHost}/patients/${id}`, patient, {
headers: new HttpHeaders({ "Content-Type": "application/json" })
});
}
public getNoAppointmentsByPatientId(patientId: number, page: number, size: number): Observable<PageRespone<Appointment>> {
return this.http.get<PageRespone<Appointment>>(
`${environment.backendHost}/patients/${patientId}/other-appointments?page=${page}&size=${size}`
);
}
}
Share
Improve this question
edited Mar 5 at 13:22
traynor
8,9123 gold badges15 silver badges28 bronze badges
asked Mar 4 at 21:40
AndreeaAndreea
1
1
- 1 This question is similar to: Angular standalone app: NullInjectorError: No provider for HttpClient. If you believe it’s different, please edit the question, make it clear how it’s different and/or how the answers on that question are not helpful for your problem. – traynor Commented Mar 5 at 13:22
1 Answer
Reset to default 0Maybe add all the providers to the app.config.ts
and then bootstrap using a config like this:
bootstrapApplication(AppComponent, appConfig)
.catch((err) => console.error(err));