Search code examples
javascriptangularangular-services

AngularJS Version 6.* Service method is coming up undefined


So I am simply trying to write a component and service that from one view takes the user input and passes it to an api for validation. The problem is that in my component, it's saying that the service essentially has no method login and is coming up undefined. However I've checked and rechecked following Angular.io's documentation very closely but can't get anything to work.

LoginComponent.ts

import { Component, OnInit } from '@angular/core';
import { UserService } from '../../../services/user.service';

@Component({
  selector: 'app-login',
  templateUrl: './login.component.html',
  styleUrls: ['./login.component.scss']
})
export class LoginComponent implements OnInit {

  constructor(private userService: UserService) {
    console.log('userService', userService);
  }

  ngOnInit() {}

  handleSubmit(data) {
    // https://api-test.sarahlawrence.edu:82/
    this.userService.login(data)
      .subscribe(user => console.log('user', user));
  }
}

user.service.ts

import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Observable, of } from 'rxjs/index';
import { catchError, map, tap } from 'rxjs/internal/operators';

const httpOptions = {
  headers: new HttpHeaders({ 'Content-Type': 'application/json' })
};

interface CredsInterface {
  username: string;
  password: string;
};

interface LoggedIn {
  token: string;
}

@Injectable({
  providedIn: 'root'
})
export class UserService {

  private apiUrl = '<apiUrl>';

  constructor(
    private http: HttpClient
  ) { }

  login (creds: CredsInterface): Observable<any> {
    console.log('UserService.login()', creds);

    return this.http.post<any>(`${this.apiUrl}/signin`, creds, {})
      .pipe(
        tap((loggedIn: LoggedIn) => {
          console.log(`Login: ${loggedIn}`);
        }),
        catchError(this.handleError('login()', []))
      );
  }

  /**
   * Handle Http operation that failed.
   * Let the app continue.
   * @param operation - name of the operation that failed
   * @param result - optional value to return as the observable result
   */
  private handleError<T> (operation = 'operation', result?: T) {
    return (error: any): Observable<T> => {

      // TODO: send the error to remote logging infrastructure
      console.error(error); // log to console instead

      // TODO: better job of transforming error for user consumption
      console.log(`${operation} failed: ${error.message}`);

      // Let the app keep running by returning an empty result.
      return of(result as T);
    };
  }
}

I don't understand why I get this error:

Error

So I logged the service out to see the object and weirdly the method is being placed in the prototype:

Prototype

I don't get it, am I doing something wrong?


Solution

  • How do you call that handleSubmit method?

    The error says that it can't read login property of undefined which means that this.userService is undefined. The fact that login method is inside prototype is okay. Remember that gets are deep and sets are shallow

    I think that you call handleSubmit with some tricky way which makes this to refer other object than you think it is.


    I've just saw stackblitz. You pass reference to your function using [onHandleSubmit]="handleSubmit" but when it's executed this is not your LoginComponent anymore.

    Add this to component constructor

    this.handleSubmit = this.handleSubmit.bind(this)
    

    For more details see this post: Angular pass callback function to child component as @Input