When attempting to loop through an Observable that is of type array using *ngFor, the error message "Cannot read property 'subscribe' of undefined

I can't figure out why this isn't working, even though it seems straightforward.

I'm using a service that gives me an observable. There are a few rxjs streams connected to it in the following way:

search(searchTerm: string {

  this.searchStream = this.http.get"${this.baseUrl}searchq=${searchTerm}");

  this.resultStream = this.searchStream.map(
    data => {
      let obj = data.json();
      return {
        artists: obj.artists.items,
        albums: obj.albums.items,
        tracks: obj.tracks.items
      };
    },
    err => console.error(err),
    () => console.log('getRepos completed')
  );

  this.albumSearchStream = this.resultStream.map(
    searchResults => {
      console.log("mapping albums");
      return searchResults.albums
    },
    err => console.log("unable to get albums")
  );
  this.albumSearchStream.subscribe(
    albums => console.log(albums)
  );
}

In short, after a request, the albumSearchStream receives an array of type EnvAlbum.

All of this is happening within a Search service.

This service is injected into my Page controller, and in the constructor, I have the following code:

this.albumResults = this.spotifyService.albumSearchStream;

where albumResults will be an Observable of type EnvAlbum[].

Then in the template, I use ngFor on this observable like this:

<ion-card *ngFor="let result of albumResults | async" >
        <ion-card-header>
            {{ result }}
        </ion-card-header>
    </ion-card>

However, I encounter the following error: https://i.sstatic.net/MGQTK.png

I'm completely puzzled as to why this error is happening.

Note: When subscribed, it correctly outputs an array of objects

Answer №1

One issue I see is that the albumResults property is not initially defined in your component, causing it to be undefined when the async pipe attempts to subscribe to it. It appears that this property is only set once you click to trigger the search method...

To resolve this, you could consider enclosing the ngFor within an ngIf statement using a desugared expression:

<template [ngIf]="albumResults"> <------
  <ion-card *ngFor="let result of albumResults | async" >
    <ion-card-header>
      {{ result }}
    </ion-card-header>
  </ion-card>
</template>

Alternatively, you can initialize the albumResults with a fake observable.

Revision

I suggest refactoring your service code as follows:

albumResults = new Subject();

search(searchTerm: string) {
  this.searchStream = this.http.get(...);

  this.resultStream = this.searchStream.map(
    data => {
      let obj = data/*.json()*/;
      return {
        artists: obj.artists.items,
        albums: obj.albums.items,
        tracks: obj.tracks.items
      };
    }
  );

  this.albumSearchStream = this.resultStream.map(
    searchResults => {
      return searchResults.albums
    }
  );
  this.albumSearchStream.subscribe(
    albums => {
      this.albumResults.next(albums);
    }
  );
}

Then, assign the albumResults property in your component like this:

constructor(private spotifyService:SpotifyService) {
  this.albumResults = this.spotifyService.albumResults;
}

Take a look at this plunkr: https://plnkr.co/edit/IrsZ9P3wff2YXyjRRGTw?p=preview.

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

Output error messages in Angular form validation explained

Exploring the functionality of this template-driven form in Angular. <form name="editForm" role="form" novalidate (ngSubmit)="save()" #editForm="ngForm"> <input #cardInput type="text" class="form-control" name="name" id="id_name" [(ng ...

ASP.NET service with an added quotation mark in the JSON response!

I am trying to make a web service method call in JavaScript within an ASP.NET 3.5 environment. After inspecting the result using Firebug, I found the following: {"d":"[{\"TI\":\"www\"},{\"TI\":\"www1\"}]"} It seem ...

The meteorite experienced a crash as startup.js attempted to connect with Mongo

Setting up a Mongo database for a meteor project has been tricky for me. I've created a startup.js file to load the necessary files, but as soon as I start meteor, it crashes. Can anyone lend a hand, please? Here is a snippet from the HTML file: < ...

Bidirectional synchronization with Angular 6 reactive forms

I'm currently working on building a complex reactive form that includes nested components populated with data objects. The functionality I'm aiming for is similar to the two-way data binding in template-driven forms: when a user modifies an inpu ...

Tips for generating multiple instances of a JavaScript function on a single page

Consider the following JavaScript code snippet : var from,to; to = $(".range-to-dt").persianDatepicker({ inline: true, minDate: new persianDate(cleanDate(serverDateTime)), altField: '.range-to-dt-alt', altFormat: ...

Ensuring proper functionality of JQModal when displayed above an iframe with the usage of ?wmode=

Here's an interesting one... I'm currently working on a site with JQModal and everything seems to be functioning properly except for the fact that the iframe appears on top of the modal. An easy fix is to append ?wmode=opaque at the end of the ...

How to iterate through an array in jQuery/JavaScript and create variables in each loop?

I've been puzzled for a while now as to why this code snippet doesn't work as intended: if (longest.length >= 3) { for ( var i = 0; i < longest.length-1; i++) { var $last[i] = longest[i].splice(-1).toString(); //if ( $( $la ...

jQuery Animation Issue: SlideDown Effect Not Working as Expected

I'm feeling quite confused about this situation. I've been attempting to utilize the slideDown function in jQuery, but when I click on the 'information' div, it just jumps instead of animating smoothly. I suspect that one of the cause ...

Angular 7 running slowly when refreshing or changing routes

Operating System: Ubuntu 16.04 Node Version: v10.15.1 NPM Version: 6.4.1 I have recently developed a web application with two pages using less and HTML without any AJAX calls. Below is the content of my package.json file: { "name": "frontend", "vers ...

An abundant array of options spread across numerous dropdown menus

I have been tasked by a client to do something new that I haven't done before, so I am seeking the best approach. The project involves creating a form with three dropdown menus where users can select from thousands of options. For instance: Users mu ...

Issues with the execution of Typescript decorator method

Currently, I'm enrolled in the Mosh TypeScript course and came across a problem while working on the code. I noticed that the code worked perfectly in Mosh's video tutorial but when I tried it on my own PC and in an online playground, it didn&apo ...

Why does attempting to access an undefined property not trigger an error?

I am curious to know why var myVar = unDef; may trigger a ReferenceError, while var myObj = {}; var myVar = myObj.unDef; runs smoothly? It simply returns undefined without any runtime issues. Despite both not being defined. ...

Acquiring the API through the callback function within a React application

I wrote a function that connects to an API and fetches data: import {API_KEY, API_URL} from "./constants"; export const getOperations = async (id, successCallback) => { try { const response = await fetch(`${API_URL}/tasks/${ ...

How can one dynamically update a page in Angular when the path is changed?

I am facing a pagination issue in Angular. Here is my HTML code: <!-- A div element for pagination part at the bottom of the page --> <div style="margin-left: 50%; margin-top: 20px; margin-bottom: 20px"> <ul class="paginat ...

Creating a three-dimensional shape using a transparent image in Three.js

Hey there! I'm currently working on creating a 3D model that features the upper and lower sides as transparent images, while the other sides are a solid color (yellow in this case). var texture = new THREE.TextureLoader().load( 'img.png' ); ...

State properties in Vuex remain unchangeable despite using mutator methods

I've encountered an issue with the code in my vuex module called user.js: import Vue from "vue"; import Vuex from 'vuex'; Vue.use(Vuex); const state = { user: { firstName: null, lastName: null, ...

Preserving client-side page state during page reloads in angular.js apps

I am currently developing a Single Page application using angular.js and I have encountered an issue that I am struggling to resolve. When performing a full page refresh in an angular app, how can we verify if the user still has a valid session? While Sta ...

Combining a pair of nested JSON arrays

Working on a dynamic form created in JavaScript using a JSON schema which has the following structure: { "questionSets": [ { "questionSetId": "example-fields", "questions": [ { "questionId": "text", "question" ...

Make sure the subset interface is selected from the interface / Choose PickDeep<>?

I am searching for a solution using the following interface: interface Person { age: number, name: string, hometown?: { city: string, zip: number } } type SubPerson = EnsureSubInterface<Person, { name: string }> an example that w ...

What is the best way to access and manipulate data stored in a Firestore map using React?

In my Firestore database, I have a field with map-like data: coordinates:{_01:"copper",_02:"gold",_03:"iron"} When viewing this database in the Firestore admin panel, it appears like this: pic However, when attempting to list items using the following c ...