Angular Standalone: NullInjectorError: No provider for HttpClient despite using...

Discussão em 'Angular' iniciado por Andreea, Março 5, 2025.

  1. Andreea

    Andreea Guest

    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 patients.component.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/app.component';
    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()]
    };



    patient.component.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: './patients.component.html',
    imports: [
    ReactiveFormsModule,
    NgIf,
    AsyncPipe,
    NgForOf,
    NgClass
    ],
    styleUrl: './patients.component.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}`
    );
    }

    }

    Continue reading...

Compartilhe esta Página