0

I'm stuck here trying to loop the observable object on my users service. The Chrome's console throws:

error_handler.js:47 EXCEPTION: undefined is not a function

Here's my code:

users.component.ts

import { Component, OnInit } from '@angular/core';
import { UserService } from '../user.service';
import { Observable } from 'rxjs/Rx';
import { User } from '../user';

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

 people: Observable<User[]>;
  constructor( private _userService: UserService) { }

  ngOnInit() {
        this.people = this._userService.getAll();
        console.log(this.people);
    }
}

users.service.ts

import { Injectable } from '@angular/core';
import { Http, Response, Headers } from '@angular/http';
import { Observable } from 'rxjs/Rx';
import { ErrorObservable } from 'rxjs/observable/ErrorObservable';
import { User } from './user';


@Injectable()
export class UserService {

  private baseurl: string= 'http://swapi.co/api';

  constructor(private http: Http) { 
      console.log("User service initialized");
  }


  getAll(): Observable<User[]>{
    let users$ = this.http
      .get(`${this.baseurl}/people`,{headers: this.getHeaders()})
      .map(this.mapUsers);

      return users$;
  }


  private getHeaders(){
    let headers = new Headers();
    headers.append('Accept', 'application/json');
    return headers;
  }


  mapUsers(response: Response): User[]{
       return response.json().results.map(this.toUser);
  }


  toUser(r:any): User{
    let user = <User>({
        id: this.extractId(r),
        name: r.name
    });
    console.log('Parsed user'+user.name);
    return user;
  }


extractId(personData:any){
    let extractedId = personData.url.replace('http://swapi.co/api/people/','').replace('/','');
    return parseInt(extractedId);
}

}

users.component.html

<ul class="people">
    <li *ngFor="let person of people | async " >
        <a href="#">
          {{person.name}}
        </a>
    </li>
</ul>

user.ts

export interface User{
    id: number;
    name: string;
}

When I remove the HTML code from the template, everything works great (no errors on console) so, I guess there's something wrong with 'people' object, and obviously I can't iterative the response. Please guys, a hand would be appreciated here.

1 Answer 1

1

The most likely reason is the way you are handling the map callback

getAll(): Observable<User[]>{
  let users$ = this.http
    .get(`${this.baseurl}/people`,{headers: this.getHeaders()})
    .map(this.mapUsers);
}

mapUsers(response: Response): User[]{
  return response.json().results.map(this.toUser);
}

toUser() {}

You need to be careful when using this inside callback functions. The context sometimes messes you up. In this case this in .map(this.toUser) does not point to the class instance. You need to bind it, i.e.

  let users$ = this.http
    .get(`${this.baseurl}/people`,{headers: this.getHeaders()})
    .map(this.mapUsers.bind(this));

When you use bind(this) you are saying that any uses of this inside the mapUsers function should be bound to the class instance.

When you use arrow functions, you don't need to worry about this distinction, as it keeps the lexical scope context

let users$ = this.http
  .get(`${this.baseurl}/people`,{headers: this.getHeaders()})
  .map(res => response.json().results.map(this.toUser));

Also, even passing the toUser function has the same problem, as you are using this.extractId(r). You also need to bind that

mapUsers(response: Response): User[]{
  return response.json().results.map(this.toUser.bind(this));
}
Sign up to request clarification or add additional context in comments.

4 Comments

Thank you pesskillet for yor reply. Good to know that.. I'll keep it on mind. I've modified the function, updating the map call: .map(this.mapUsers.bind(this)); ... but now the console throws: Uncaught Error: Module build failed: Error: /home/webdeveloper/Workspace/Angular2/unibague_directory_v2/src/app/user.service.ts (26,14): Type 'Observable<{}>' is not assignable to type 'Observable<User[]>'. Type '{}' is not assignable to type 'User[]'.
And if I use the second option (res =>) my code editor (visual studio) underlines the "response" word. (variable not declared)
Well, yeah, it was a typo. It should be response, not res
Hey peeskillet, thank you very very much.. it works now. You made my day.

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.