Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NestJS Inject module service inside in a non module file

I have a function file for view render and i want to use nestjs modules service in here. My render file is like this.

export default {
  parse() { }
  render() { }
}

So to use module service in here i tried to inject like this.

import { Inject } from '@nestjs/common';
import { MemberService } from './member.service';

class SampleClass {
  constructor(@Inject('MemberService') private readonly memberService: MemberService) {}
}

// Creating class in here to use in functions
const sampleService = new SampleClass();

export default {
  parse() { }
  render() { }
}

When i try to create new class in here i got error "Expected 1 arguments but got 0"

My MemberService is like this

@Injectable()
export class MemberService {
  constructor(@Inject(Constants.RelationshipMemberModel) private readonly relationshipMemberModel: typeof Model) {}
  login () {}
}

So how should i inject service to use in this file ?

like image 891
Taha Ergun Avatar asked Aug 21 '19 11:08

Taha Ergun


2 Answers

In order to Inject a provider the component has to belong to a context (Basically a module) in the nest application, basically it has to be or a Injectable, Controller, Async Provider or a Custom Async Provider, and it has to belong to a Module in which it has access to the provider you are trying to inject. In order to use a functionality of a service in external javascript classes that are not in a context you can import the service and you gotta instantiate it by yourself here you can have an example of this aproach:

class SampleClass {
  private memberService: MemberService; 
  constructor() {
    this.memberService = new MemberService();
  }
}

Remember this is another instance of the service and if you don't take care you will have multiple instances on runtime as it is not an injectable anymore but a class object. In order to prevent this maybe you can create a singleton containing all the MemberService functionality and import it in both the MemberService and the SampleClass:

export class MemberFunctionality {
  private static memberFunctionality: MemberFunctionality;
  private constructor() {}
  static getInstance(): MemberFunctionality {
    if(!memberFunctionality) {
      this.memberFunctionality = new MemberFunctionality();
    }
    return this.memberFunctionality;
  }
  login() {}
}

Then you import it on both MemberService and SampleClass and call the getInstance method

import { MemberFunctionality } from './member-functionality.ts';

class SampleClass {
  private memberFunctionality: MemberFunctionality;
  constructor() {
    this.memberFunctionality = MemberFunctionality.getInstance();
  }
  ...
}

same goes for the MemberService

import { MemberFunctionality } from './member-functionality.ts';

@Injectable()
export class MemberService {
  private memberFunctionality: MemberFunctionality;
  constructor(@Inject(Constants.RelationshipMemberModel) private readonly relationshipMemberModel: typeof Model) {
    this.memberFunctionality = MemberFunctionality.getInstance();
  }
  login () {
    return this.memberFunctionality.login();
  }
}

And that would take care of only having an instance of that functionality

like image 119
RalphJS Avatar answered Oct 12 '22 15:10

RalphJS


I did it 2 different way

  1. In your module, listen to OnApplicationBootstrap and inject it manually yourself

     import { Module, OnApplicationBootstrap } from '@nestjs/common';
     import { ModuleRef } from '@nestjs/core';
     import { SampleClass } from 'src/commons/SampleClass';
     import { MemberService } from 'src/module/MemberService';
    
     export class YourAwesomeModule implements OnApplicationBootstrap {
       constructor(private moduleRef: ModuleRef) {}
       onApplicationBootstrap() {
           // implement singleton here
         const sampleClass = SampleClass.getInstance();
         const memberService = this.moduleRef.get(MemberService);
         sampleClass.setMemberService(memberService);
       }
     }
    

Actually you can just pass this into SampleClass from the constructor of MemberService if decouple is not required.

  1. For a similar case (pass instance between different module), I use the UseGuard, add instance to request object from another module and use it in Controller/Service class.
like image 44
benbai123 Avatar answered Oct 12 '22 13:10

benbai123