Angular Dependency Injection — Inject service inside custom Rxjs operators

madhust

Madhu Sudhanan P

Posted on November 24, 2024

Angular Dependency Injection — Inject service inside custom Rxjs operators

Angular is an opiniated framework. It’s really an excitement to see how its diverging towards developer flexibility and becoming stronger day by day. I believe it’s a happy era for the Angular lovers.

Dependency injection and RxJS — In my opinion, are powerful features which made Angular unique and flexible. RxJS custom operators are a great way to compose complex logic into reusable functions.

Recently I came across a usecase where I need to create a custom RxJS operator which uses service to achieve some complex usecase.

You can use inject method to access desired service instance, inject must be used within dependency injection context though. To achieve this, Rxjs operator can be registered as a InjectionToken which uses useFactory function to instantiate its value. Since useFactory is a injection context, the services can be injected without any problem using the inject method.

Let’s see how the below service can be injected in a rxjs custom operator.

// Service
@Injectable({
  providedIn: 'root',
})
export class Multiplier {
  public transfrom(val: number) {
    return val * 2;
  }
}
Enter fullscreen mode Exit fullscreen mode

The below custom RxJS operator simply multiple the given value with 2 using the Multiplier service.

import { inject, InjectionToken } from '@angular/core';
import { Multiplier } from '../services/multiplier';
import { map, OperatorFunction, pipe } from 'rxjs';

export const MULTIPLIER_OPERATOR: InjectionToken<OperatorFunction<number, number>>
  = new InjectionToken('Multipler operator', {
    factory(): OperatorFunction<number, number> {
      const multipler = inject(Multiplier); // injected Multipler service
      return pipe(map((x: number) => multipler.transfrom(x)));
    },
  });
Enter fullscreen mode Exit fullscreen mode

Now the custom operator can be used within the components using the @Inject decorator.

import { Component, Inject } from '@angular/core';
import { BehaviorSubject, Observable, of, OperatorFunction } from 'rxjs';
import { MULTIPLIER_OPERATOR } from './rxjs-operators/custom';
import { CommonModule } from '@angular/common';

export class App {
  private _count = 1;
  public base = new BehaviorSubject(this._count);
  public val = new Observable();

  constructor(
    @Inject(MULTIPLIER_OPERATOR) // injected custom operator
    private multiplier: OperatorFunction<number, number>) {
      this.val = this.base.pipe(this.multiplier); // used rxjs operator
  }

  .....
}
Enter fullscreen mode Exit fullscreen mode

Image description

There are several other ways to achieve this same usecase like creating a separate service and a method that would return custom operator. But I like InjectionToken approach due to its self containability. RxJS isn’t going anywhere in near future even with introduction of signals so it’s worth experimiting on it.

You can see the full working example here.

Happy Coding…🎉

💖 💪 🙅 🚩
madhust
Madhu Sudhanan P

Posted on November 24, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related