最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

Angular Standalone: NullInjectorError: No provider for HttpClient despite using provideHttpClient() - Stack Overflow

programmeradmin1浏览0评论

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
Add a comment  | 

1 Answer 1

Reset to default 0

Maybe 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));

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论