4

I am calling a function from a service, but I always get Cannot read property 'getCurrentUser' of undefined.

This is my service, authentication.service.ts

import { Injectable } from '@angular/core';
import { Http, Headers, Response, RequestOptions } from '@angular/http';
import { Observable } from 'rxjs';
import 'rxjs/add/operator/map';

@Injectable()
export class AuthenticationService {
  public token: string;
  private url = 'http://192.168.201.211:8024/api-token-auth/';
  private options: RequestOptions;
  private currentUser: any;

  constructor(private http: Http) {
    // set token if saved in local storage
    this.currentUser = JSON.parse(localStorage.getItem('currentUser'));
    this.token = this.currentUser && this.currentUser.token;
    let headers = new Headers({ 'Content-Type': 'application/json' });
    this.options = new RequestOptions({ headers: headers });
   }

  login(username: string, password: string): Observable<boolean> {
    return this.http.post(this.url, JSON.stringify({ username: username, password: password }), this.options)
        .map((response: Response) => {
            // login successful if there's a jwt token in the response
            let token = response.json() && response.json().token;
            if (token) {
                // set token property
                this.token = token;

                // store username and jwt token in local storage to keep user logged in between page refreshes
                localStorage.setItem('currentUser', JSON.stringify({ username: username, token: token }));

                // return true to indicate successful login
                return true;
            } else {
                // return false to indicate failed login
                return false;
            }
        });
  }

  logout(): void {
    // clear token remove user from local storage to log user out
    this.token = null;
    localStorage.removeItem('currentUser');
  }

  getCurrentUser(): Observable<any> {
    console.log('i am in getCurrentUser');
    this.currentUser = JSON.parse(localStorage.getItem('currentUser'));
    return this.currentUser;
  }
}

Then, I call getCurrentUser from another component user-detail.component.ts:

import { Component, OnInit, Input } from '@angular/core';

import 'rxjs/add/operator/switchMap';
import { User } from '../user';
import { AuthenticationService } from '../authentication.service';

@Component({
  selector: 'app-user-detail',
  templateUrl: './user-detail.component.html',
  styleUrls: ['./user-detail.component.css']
})

export class UserDetailComponent implements OnInit {
  @Input() user: User;  // current page belonger
  loginUser: any;  // current login user
  canEdit: boolean = false;
  constructor(
    private authService: AuthenticationService,
  ) {
   }

  ngOnInit() {

    // always watch out login user
    setInterval(this.checkUserMatch, 5000);
  }


  //  check if current login user can edit this page
  checkUserMatch() {
    this.loginUser = this.authService.getCurrentUser();
    if (this.loginUser) {
      if (this.user.username === this.loginUser.username) {
        this.canEdit = true;
      }
      else {
        this.canEdit = false;
      }
    }
    else {
      this.canEdit = false;
    }
    console.log(this.canEdit);
  }
}
4
  • Are you sure you have a value in your localStorage.getItem('currentUser')? can you do a console log after getting it from the local storage? Commented Aug 31, 2017 at 3:17
  • You have a small misstake in returning value of getCurrentUser() it's Observable, but you try to return object. Commented Aug 31, 2017 at 3:21
  • Have you registered the service in the app.module.ts file? Commented Aug 31, 2017 at 3:31
  • I solved this problem through @Saravana's answer, thank you all. Commented Aug 31, 2017 at 3:59

1 Answer 1

10

The context of this changes inside checkUserMatch when you pass a reference to setInterval like this setInterval(this.checkUserMatch, 5000);.

Use arrow function to wrap the function. This will set the correct this inside checkUserMatch``:

setInterval(() => this.checkUserMatch(), 5000);

Or use Function.bind:

setInterval(this.checkUserMatch.bind(this), 5000);

See red flags for this.

Sign up to request clarification or add additional context in comments.

4 Comments

It saved me, actually I used to write setInterval(() => this.checkUserMatch, 5000), then it didn't work, because I forgot ().
Both methods work fine, I think these things about this may be the hardest thing to understand in js.
This might help you understand.
@Saravana So, if I use bind function, if I put on the same function for example this.updateView() it will try to call updateView from the service and not from the current page?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.