Injecting a useFactory provider in Angular is a common practice

I manage a factory provider service that selects a service based on a flag. Everything works fine when I need a debug students service, but when I set the flag to false, the application throws an ERROR TypeError: serverService.fetchData is not a function. How can this be resolved?

Students.provider
import { StudentDebugService } from "./student-debug.service";
import { StudentService } from "./student.service";
import { ServerService } from "./server.service";

const isNeedDebug: boolean = false;

const studentServiceFactory = (studentDebugService: StudentDebugService, serverService: ServerService) => {
  if (isNeedDebug) {
    return new StudentService(studentDebugService.students);
  }
  serverService.fetchData().subscribe( (students) => {
    return new StudentService(students);
  });
};

export let studentServiceProvider = {
  provide: StudentService,
  useFactory: studentServiceFactory,
  deps: [ServerService, StudentDebugService]
};

StudentsService
import { Inject, Injectable } from "@angular/core";

export interface StudentsArgs {
  id: number;
  surName: string;
  name: string;
  middleName: string;
  birthday: string;
  averageRate: number;
}

@Injectable({providedIn: "root"})
export class StudentService {
  constructor(@Inject(StudentService)public students: StudentsArgs[]) {
  }
  getStudents(): StudentsArgs[] {
    return this.students;
  }
}
ServerService
import { HttpClient } from "@angular/common/http";
import { Injectable } from "@angular/core";
import { Observable } from "rxjs";


@Injectable({providedIn: "root"})
export class ServerService {
  constructor(private http: HttpClient) {
  }
  fetchData(): Observable<any> {
    return this.http.get("http://localhost:3000/api");
  }
}

The StudentsProvider component should inject the necessary service in app.component.constructor

App.Component.ts
import {ChangeDetectionStrategy, Component, Inject, OnInit} from '@angular/core';
import { StudentsArgs, StudentService } from "./services/student.service";


@Component({
  selector: "app-root",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.css"],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class AppComponent implements OnInit {
  students: StudentsArgs[] = [];

  constructor(private studentService: StudentService) {
  }
  ngOnInit(): void {
    console.log(this.studentService);
    this.students = this.studentService.students;
  }

App.module.ts

import { NgModule } from "@angular/core";
import { BrowserModule } from "@angular/platform-browser";

import { HttpClientModule } from "@angular/common/http";
import { FormsModule } from "@angular/forms";
import { AppComponent } from "./app.component";
import { studentServiceProvider } from "./services/student.service.provider";
import {ServerService} from './services/server.service';
import {StudentDebugService} from './services/student-debug.service';

@NgModule({
  declarations: [
    AppComponent,
  ],
  imports: [
    BrowserModule,
    FormsModule,
    HttpClientModule,
  ],
  providers: [studentServiceProvider],
  bootstrap: [AppComponent]
})
export class AppModule { }

Answer №1

It turns out that the issue was due to the order of dependencies being important.

All you need to do is switch your deps:

deps: [StudentDebugService, ServerService]

For more information, check out this StackBlitz

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Refresh the content of an Angular modal with updated data each time the modal is launched

Currently, I am working on an angular web project that involves a main component class loading a Modal to update a report. Within this Modal, there are tabs - one of which is the transaction tab for which I am responsible. However, I have encountered an is ...

"Disabling a FormControl within a FormArray in Angular 4: A Step-by-

I've come up with a code snippet below that I thought would disable the FormControl in a FormArray. some.component.html <form [formGroup]="testForm"> <div *ngFor="let num of countArr"> <input type="text" formNameArray="arr ...

What is the best way to prevent external scrolling when the mat-autocomplete panel is displayed?

When trying to open a mat-autocomplete in Angular Material, I noticed that the background content is still able to scroll. I attempted using the block strategy but it didn't have the desired effect. ...

Creating Personalized Validators for Angular Version 5 Reactive Forms

I am struggling to create a custom validator for my Angular v5 application. I followed the documentation for a basic password match example in the Docs, but it's not working as expected. this.personalInfoForm = _fb.group({ 'name': [null,V ...

I need to create a login form using Angular - what steps should I follow?

I'm currently in the process of developing a login form for my website. Utilizing angular, express, and mongoDB. Below is the login function controller I have implemented: loginUser: (req, res) => { User.findOne({ username: req.bo ...

Guide to slicing strings specifically with numerical characters at the end

I've encountered a challenge. I need to slice the last two characters in a string, but only for strings that contain numbers. I attempted using "nome": element.nome.slice(0,-2) and now I require some sort of validation. However, figuring out how to do ...

Is there a way to verify if a value is undefined before including it as an object field?

I'm currently working on an Angular project and I have a query regarding TypeScript. It's about correctly handling the scenario where a field should not be included in an object if its value is undefined. In my code, I am initializing an object ...

How can I take photos in bulk when I open the camera on Ionic 3?

Is there a way to capture multiple images at once using the camera? Currently, I am only able to capture one image when the user clicks. However, I would like to capture four images when the user clicks the success button. let options: CaptureImageOption ...

The Angular/Express application is in search of outdated JavaScript files within the Chrome browser

When updating and deploying my Angular web app on Google App Engine with an Express server, I encounter a peculiar issue. Upon refreshing the browser, I sometimes face a blank page accompanied by the following error: main.f2b54282bab6f51a.js:1 Failed to lo ...

Spying on ActivatedRoute.queryParams is not possible in Angular when using Jasmine

Is there a way to effectively spy on a stubbed Angular Service method that should return an Observable like ActivatedRoute.queryParams? The below code snippet shows my failing test case: import { TestBed, ComponentFixture } from "@angular/core/testing"; i ...

Angular 2 routing for dynamic population in a grid system

My website is compiling correctly, however, in the Sprint dropdown menu where I have set up routing... <a *ngFor = "let item of sprint;" routerLink = "/Summary" routerLinkActive = "active"> <button *ngIf = "item.Name" mat-menu-item sty ...

Navigate to the parent element in the DOM

Looking to add some unique styling to just one of the many Mat dialog components in my project. It seems like modifying the parent element based on the child is trickier than expected, with attempts to access the DOM through the <mat-dialog-container> ...

The name 'Firebase' is not recognized by Typescript

Encountering typescript errors while building a project that incorporates angularfire2 and firebase. Here are the packages: "angularfire2": "^2.0.0-beta.0", "firebase": "^2.4.2", Listed below are the errors: [10:58:34] Finished 'build.html_css&apos ...

How can one define a getter within an interface?

One of my classes is structured like this (only showing a portion here): export class LinkedListNode<t> extends windward.WrObject implements ILinkedListNode<t> { public get next(): LinkedListNode<t> { return this._next === thi ...

A guide to simulating ngControl in a Custom Form Control for effective unit testing in Angular

I need some guidance on creating unit tests for a Custom Form Control in Angular 9. The issue arises with this line of code: constructor(@Self() private ngControl: NgControl), which triggers an error: Error: NodeInjector: NOT_FOUND [NgControl]. It seems th ...

The @Input() property within an Angular component is producing an empty array as its result

I have a calendar component that has a data property marked as @Input(): import { Component, OnInit, Input, OnChanges, SimpleChanges } from '@angular/core'; @Component({ selector: 'app-calendar', templateUrl: './calendar.comp ...

Tips for sending a value to a container component

Within my task management application, I have implemented two selectors: export const selectFilter = (state: RootState) => state.visibilityFilter export const selectVisibleTodos = createSelector( [selectTodos, selectFilter], (todos: Todo[], filter : ...

Encountering challenges with the angular2-infinite-scroll plugin

I encountered 2 errors while using my application: Failed to load resource: the server responded with a status of 404 (Not Found) http://localhost:3002/angular2-infinite-scroll angular2-polyfills.js:1243 Error: XHR error (404 Not Found) loading htt ...

Divide Angular ngFor into separate divs

Here is an example of my current array: [a, b, c, d, e, f, g, h, i] I am aiming to iterate through it using ngFor and split it into groups of 3 elements. The desired output should look like this: <div class="wrapper"> <div class="main"> ...

Tips for creating PrimeNG tables with columns that automatically adjust in size

Is there a way to automatically adjust and resize the columns in my PrimeNG table? I'm looking for a method to make this happen. Can you help me achieve this? ...