1

How should I import loginMember in Controller? I am developing a REST API and now I need to use code in a different file location. I am having an error in the controller. When I am calling loginMember. (Cannot find name 'loginMember'.ts(2304))

SERVICE

import MembersModel from '../models/MembersModel';
import BaseService from './BaseService';
import { createPasswordToHash } from '../scripts/utils/auth';
class MembersService extends BaseService {  
  constructor() {
    super(MembersModel);
  }

  // loginMember
  loginMember = async (email: any, password: any) => {
    return new Promise(async (resolve, reject) => {
      try {
        let data = await this.BaseModel.findOne({
          email: email,
          password: createPasswordToHash(password),
        });
        return resolve(data);
      } catch (error) {
        return reject(error);
      }
    });
  };
  
}

export default MembersService;

CONTROLLER

import BaseController from './BaseController';
import MembersService from '../services/MembersService';
import ApiError from '../errors/ApiError';
import { NextFunction, Request, Response } from 'express';
import { createPasswordToHash, generateAccessToken } from '../scripts/utils/auth';
import httpStatus from 'http-status';

class MembersController extends BaseController {
  constructor(membersService: MembersService) {
    super(membersService);    
  }

login = (req: Request, res: Response, next: NextFunction) => {
  MembersService.loginMember(req.body)
    .then((response: any) => {
      if (response) {
        const member = {
          ...response.toObject(),
          accessToken: generateAccessToken(response.toObject()),
        };
        delete member.password;
        delete member.createdAt;
        delete member.updatedAt;
        return res.status(httpStatus.OK).send(member);
      }
      return res.status(httpStatus.UNAUTHORIZED).send({ error: 'Invalid email or password' });
    })
    .catch((err: { message: string }) => {
      return next(
        new ApiError(err.message, httpStatus.UNAUTHORIZED, 'login', req.headers['user-agent']?.toString() || 'Unknown')
      );
    });
};
  
}
export default new MembersController(new MembersService());

Now I am gettig a new error: "Property 'loginMember' does not exist on type 'typeof MembersService'.ts(2339)"

Stephen Ostermiller
  • 23,933
  • 14
  • 88
  • 109
Volvoks
  • 15
  • 6
  • This question has some answers already - if you search for "use class method in another class javascript" in google you'll see this post: https://stackoverflow.com/questions/39175922/how-to-access-a-method-from-a-class-from-another-class That should answer your question, lmk if you still need help – Zevgon Apr 05 '22 at 01:24
  • But i am calling from another file. – Volvoks Apr 05 '22 at 06:27
  • @Zevgon i am trying `MembersService.loginMember(req.body)` but error says Property 'loginMember' does not exist on type 'typeof MembersService'.ts(2339) – Volvoks Apr 05 '22 at 06:50
  • that's because the method is not static in MemberService. There are a few ways you can fix this: 1. Define the `loginMember` method as static by replacing `loginMember` with `static loginMember` in MemberService. 2. Create a new instance of MemberService in MembersController by replacing `MembersService.loginMember` with `new MembersService().loginMember`. 3. Add `this.memberService = memberService` in the constructor and then call `this.memberService.loginMember` See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/static for info about static methods – Zevgon Apr 05 '22 at 09:12
  • sorry, I didn't notice that the keyword `this` is used in the `loginMember` method. That means that the 2nd and 3rd options in my previous comment are the only ones that will work. – Zevgon Apr 05 '22 at 09:34

1 Answers1

0

You're trying to call loginMember as a static method, but it's not defined as one. You'll have to use an instance of MembersService to use the method. Since your MembersController is already being initialized with a MembersService instance, you may just want to have a membersService property on the MembersController. Also, the loginMember method takes an email and a password, so you'll have to pass those arguments explicitly instead of just passing the request body. (I'm not sure where the email and password are in the request body though, so I can't help you there.) So with those changes, it would look like:

class MembersController extends BaseController {
  private membersService: MembersService;

  constructor(membersService: MembersService) {
    super(membersService);
    this.membersService = membersService;
  }

login = (req: Request, res: Response, next: NextFunction) => {
  this.membersService.loginMember(email, password) // <- Get these from the request
    .then((response: any) => {
      if (response) {
        const member = {
          ...response.toObject(),
          accessToken: generateAccessToken(response.toObject()),
        };
        delete member.password;
        delete member.createdAt;
        delete member.updatedAt;
        return res.status(httpStatus.OK).send(member);
      }
      return res.status(httpStatus.UNAUTHORIZED).send({ error: 'Invalid email or password' });
    })
    .catch((err: { message: string }) => {
      return next(
        new ApiError(err.message, httpStatus.UNAUTHORIZED, 'login', req.headers['user-agent']?.toString() || 'Unknown')
      );
    });
};

One other code style suggestion would be to use async await instead of .then in the login method. Also, the Promise wrapping in the loginMember method looks unnecessary, and using an async function as the argument is an antipattern. The following should get the job done while avoiding those pitfalls:

  loginMember = (email: any, password: any): Promise<Response> => {
    return this.BaseModel.findOne({
      email: email,
      password: createPasswordToHash(password),
    });
  };
Zevgon
  • 556
  • 4
  • 13
  • Thank u so much @Zevgon. Everything seems fine. But when I try to login, I get 'Invalid email or password' warning even if the mail and password are correct. – Volvoks Apr 05 '22 at 12:56
  • ``.loginMember(req)`` is the **req** here wrong code? – Volvoks Apr 05 '22 at 13:18
  • Yes, `.loginMember(req)` will fail because the `loginMember` function is expecting an email and a password, not a request object. So you'll have to find the email and password in the request, and then pass them as 2 separate arguments: `.loginMember(email, password)` – Zevgon Apr 05 '22 at 14:48
  • i edit loginMember like this ``.loginMember( { email: req.body.email, password: req.body.password } )``, i am getting 'Invalid email or password' again. Should i change ``.then((response: any) => ...)`` to ``.then((email: res.body.email, password: res.body.password) => ...)`` – Volvoks Apr 06 '22 at 06:33
  • Ah ok, there was an error in the if construction. – Volvoks Apr 06 '22 at 07:04
  • You're still passing a single argument into the `loginMember` method, which won't work. `{ email: req.body.email, password: req.body.password }` is a single object, and that's what you're using as the argument. You have to provide 2 arguments that are not wrapped inside an object, so like this: `.loginMember(req.body.email, req.body.password)` – Zevgon Apr 06 '22 at 20:02
  • I won't be able to help with any more debugging of this unfortunately, since we've already drifted away from the main purpose of StackOverflow, which is individual questions and answers rather than debugging several items at once. Most of these individual issues should have answers elsewhere in StackOverflow, although I know it can be hard to know what to look for when you're just starting out.... I'd probably suggest a tutor, or a JavaScript tutorial like CodeCademy to get familiar with these concepts of arguments, promises, objects, class methods, etc. – Zevgon Apr 06 '22 at 20:14