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:
So I logged the service out to see the object and weirdly the method is being placed in the prototype:
I don't get it, am I doing something wrong?
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