MD10
MD10

Reputation: 1521

How to use @Inject and get the instance of the service not in the constructor?

I have a generic class that uses http inside it:

export abstract class GenericCrudService<T> {
  constructor(protected http: HttpService, protected resourse: Resourse) {}

  private entities: T[] = [];
  entitiesChanged$: Subject<T[]> = new Subject();

  getAllEntities() {
    this.http.get<T>(environment.endpoint + this.resourse).subscribe((res) => {
      this.entities = res;
      this.entitiesChanged$.next(this.entities);
    });
  }

  createEntity(entity: T) {
    return this.http
      .post(environment.endpoint + this.resourse, entity)
      .subscribe((_) => {
        this.entities.push(entity);
        this.entitiesChanged$.next(this.entities);
      });
  }
  deleteEntity(id: string) {
    return this.http
      .delete(environment.endpoint + this.resourse, id)
      .subscribe((res: any) => {
        this.entities = this.entities.filter((e: any) => e._id !== res.deleted);
        this.entitiesChanged$.next(this.entities);
      });
  }

  updateEntity(id: string, newEntity: T) {
    return this.http
      .put(environment.endpoint + this.resourse, id, newEntity)
      .subscribe((res: any) => {
        const updatedIndex = this.entities.findIndex(
          (e: any) => e._id === res.updated
        );
        this.entities[updatedIndex] = newEntity;
        this.entitiesChanged$.next(this.entities);
      });
  }

  getLatestEntities() {
    return this.entitiesChanged$.asObservable();
  }
}

also have this service that extends that class:

@Injectable({
  providedIn: "root",
})
export class ExerciseService extends GenericCrudService<IExercise> {
  constructor(http: HttpService) {
    super(http, Resourse.exercise);
  }
}

I thought it would be nicer to not inject the http client in the exercise service as it doesnt need it, and create it only in the generic one by doing something like:

@Inject(HTTP_TOKEN?) http : HttpService and use this.http everywhere in the service. My question is, is it possible and recommended and also if so how can I get the HttpService injection token, or how can I create one if it doesnt exist?

Upvotes: 0

Views: 2860

Answers (1)

Andrei
Andrei

Reputation: 12021

there is only one "elegant" way to inject anything in Angular and that is the constructor way. The other way is to inject Injector in the constructor and Injector.get(token) at any moment of runtime.

myService = this.injector.get(MyService);
constructor(private injector: Injector) {}

in your code it would be

export abstract class GenericCrudService<T> {
  protected http = this.injector.get(HttpService);
  constructor(protected injector: Injector, protected resourse: Resourse) {}
...
}
....
export class ExerciseService extends GenericCrudService<IExercise> {
  constructor(injector: Injector) {
    super(injector, Resourse.exercise);
  }
}

then in any descendants you would only pass the injector to parent, and parent may inject whatever it wants with the help of this injector

UPDATE: it is no longer necessary to inject the Injector to query all of the dependencies without using constructor. From Angular 14 there is an inject global function exposed

class SomeComponent {
  myService = inject(MyService);
  ...

Upvotes: 3

Related Questions