Encountering a problem when attempting to iterate through Observable Objects in Angular 2

I've hit a roadblock trying to iterate through the observable object in my users service. The error thrown by Chrome's console is:

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

Below is the code causing the issue:

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, it seems there's an issue with the 'people' object that I can't iterate through properly. Any help would be greatly appreciated.

Answer №1

The likely cause of the issue lies in how you are managing the callback for the map function.

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() {}

It's important to be cautious when using this within callback functions since the context can sometimes lead to confusion. In this scenario, this in .map(this.toUser) does not refer to the class instance. You must bind it, like so:

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

By using bind(this), you specify that any uses of this inside the mapUsers function should be linked to the class instance.

When employing arrow functions, you eliminate the need to be concerned about this distinction, as they preserve the lexical scope context.

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

Furthermore, passing the toUser function encounters the same issue, as you utilize this.extractId(r). Binding is necessary in this case as well.

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

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What benefits does utilizing a liquid template in Azure Logic Apps offer when it comes to transforming XML data?

Converting XML to JSON in logic apps is as easy as calling json(xmlStringHere), so it begs the question: why would we need a liquid template? ...

What is the optimal table format for converting JSON data to MySQL?

The JSON file below contains data on cards from the Magic 2014 Core Set... { "name":"Magic 2014 Core Set", "code":"M14", "releaseDate":"2013-07-19", "border":"black", "type":"core", "cards": [ { "layout":"no ...

Updating a JSON string with Regular Expressions

Is there a way to perform a global string replacement operation like the one below using regular expressions? var d = "{\"AlertDate\": \"\/Date(1277334000000+0100)\/\",\"Progress\": 1,\"ReviewPeriod\": 12} ...

Removing all repetitions from an array in JavaScript

My collection of objects includes the following inputs: var jsonArray1 = [{id:'1',name:'John'},{id:'2',name:'Smith'},{id:'3',name:'Adam'},{id:'1',name:'John'}] There is a dupl ...

The function findOne in Mongoose can result in a null or undefined value

Whenever I try to fetch data from the database in my /authenticate route, I am consistently getting null/undefined as a result. Despite successfully establishing a connection and confirming the existence of the user in the database using Robo 3T, this issu ...

Angular 6 and Bootstrap 4 unite in a powerful collaboration, showcasing a stunning carousel feature enhanced with dynamic

Currently I am working on creating a carousel using Bootstrap 4 and Angular 6. Everything is functioning properly, except for one issue that I am facing. I am trying to add Indicators dynamically by using a *ngFor loop. The problem I am encountering is tha ...

You are unable to apply 'use client' on a layout element in Next.js

While attempting to retrieve the current page from the layout.txt file, I encountered errors after adding 'use client' at the top of the page: Uncaught SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data parseMod ...

The associated type 'Iterator' of type 'DecodedArray<T>' is not valid

I am currently attempting to parse data using the tutorial linked below However, I encountered an error: Reference to invalid associated type 'Iterator' of type 'DecodedArray' ** subscript(index: Index) -> Iterator.Element { ...

Transform tuples into a list of dictionaries

I've encountered some difficulty transforming two tuples into a list of dictionaries. The structure is as follows: train_detail = (Counter({2: 50, 0: 62, 1: 38}), {2: 0.3333333333333333, 0: 0.41333333333333333, 1: 0.25333333333333335}) test_detail = ...

Performing aggregation functions on arrays of JSON data in PostgreSQL

Many discussions mention using json_array_elements to extract elements from a JSON array, but it seems to only work on a single array. When attempting to use it in a general query, an error occurs: ERROR: cannot call json_array_elements on a scalar Cons ...

Icon that can be clicked in a div container

Is there a way to prevent the div click event from being triggered when clicking on ion-icon? <div(click)="goNext()"> <ion-icon name="close-circle-outline" size="large" (click)="dissmiss()"></io ...

What is the correct way to format object IDs and dates in json serialized mongodb data in a .net environment?

Can you help me with formatting object ids and dates correctly in the json serialized output using .net? return Json(result, JsonRequestBehavior.AllowGet); Here is the current output that I am receiving { "_id": { o "Timestamp": 1321487136, ...

Unusual Behavior of Observable.concat() in Angular 4 with RxJS 5

My Angular 4 / TypeScript 2.3 service has a method called build() that throws an error if a certain property is not initialized. I am attempting to create a safer alternative called safeBuild() that will return an Observable and wait for the property to be ...

Combine form data from a reactive form into a string using interpolation

Currently, I am working with an object that has a string property embedded within it. The string in this property contains interpolation elements. For my user interface, I have implemented a reactive form with an input field. My goal is to display the ent ...

Modifying styles/css in Angular2 using JavaScript results in a temporary change in styles before ultimately reverting back to the original styles

Recently, I encountered an issue while trying to change styles for some elements in Angular 2 using JavaScript. Interestingly, when the view is loaded, the height is initially set to maxHeight = 100, but after a few milliseconds, it reverts back to the o ...

Struggling to configure Connected React Router correctly

As I work on updating my React, Redux, and Router versions to incorporate connected-react-router, I've encountered an issue with the root reducer and store creation process. The previous functioning reducer code looked like this: const appReducer = ...

Having Trouble Retrieving Data from Observable in Angular 2 and Typescript

I've encountered a promise error when trying to access a variable that receives data from an observable. Here's an example: Within my component, I have defined the Stat class: export class Stats { name: string; percentage: number; constru ...

The primeng MenuItem component does not have a 'command' property and is of type 'never'

I am currently working on implementing a primeng ContextMenu using the Menu Model API. Within the MenuItem object, there is a property named "command" which, to my understanding, should be a function. As I am receiving the available context menu items fro ...

Deciphering a two-dimensional JSON array within an Android application, followed by placing the data into intents and retrieving their values in a separate activity

I have a 2D array in Android that I need to parse and pass as an intent to another activity. Can someone help me with this? Below is the 2D array that I receive from the server: [ { "sno": "131", "email": "<a href="/cdn-cgi/l/email-protection" ...

What steps should be followed in order to generate a child or item with no assigned key

Here is my TypeScript code designed to automatically record the time of data creation: import * as functions from 'firebase-functions'; export const onAccCreate = functions.database .ref('/Agent/{AgentID}') .onCreate((snapshot, contex ...