Generate md-card components in real-time using data fetched from an API

I have a scenario where I make an API call to fetch user profiles, and I want to generate Angular Material Design md-cards dynamically for each profile. The number of profiles retrieved can vary, hence the need for dynamic card creation.

Below is the component file responsible for making the JSONP request and storing the profiles in the profiles variable:

import {Component, Injectable, OnInit} from '@angular/core';
import {Jsonp} from '@angular/http';

@Component({
  selector: 'app-staff',
  templateUrl: './staff.component.html',
  styleUrls: ['./staff.component.css']
})
@Injectable()
export class StaffComponent implements OnInit {
  public searchField: string;
  apiUrl = 'this/is/my/api/url';
  public results: JSON;
  public profiles;

  constructor(private jsonp: Jsonp) {
  }

  ngOnInit() {
  }

  setSearchField(field: string){ // ignore this method
    this.searchField = field;
    console.log('Received field: ' + this.searchField);
  }

  search(term: string) {
    const apiUrl = `${this.apiUrl}?search=${term}&rows=10&callback=JSONP_CALLBACK`;
    return this.jsonp.request(apiUrl).map(results => { this.results = results.json(); console.log(this.results['profiles'][0]); this.profiles = results['profiles']; return results.json(); });
  }

}

This is the template section pertaining to the above component, where I attempt to use *ngFor to create a list of md-card:

<div class="container-fluid">
  <div class="row justify-content-center">
    <div class="col-md-auto">
      <ul>
        <li *ngFor="let profile of profiles">
          <md-card class="example-card">
            <md-card-header>
              <div md-card-avatar class="example-header-image"></div>
              <md-card-title>{{profile.fullName}}</md-card-title>
              <md-card-subtitle>Department</md-card-subtitle>
            </md-card-header>
            <img md-card-image src="../assets/image.png">
            <md-card-content>
              <p>
                This section of the card will contain information about the result being searched for. It could also be
                accompanied by additional information such as links.
              </p>
            </md-card-content>
            <md-card-actions>
              <button md-button>APPLY</button>
              <button md-button>GO TO xyz</button>
            </md-card-actions>
          </md-card>
        </li>
      </ul>
    </div>
  </div>
</div>

The profile data is stored in an array format (assuming a maximum length of 10) with the following structure:

0: {fullName: "Foo Bar", emailAddress: "<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="b8ded7d7dad9caf8ded7d7dad9ca96dbd7d5">[email protected]</a>", image: "/profile/image/foobar/foobar.jpg", phoneNumber: "99999999"},

1: {fullName: "Foo Bar1", emailAddress: "<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="abcdc4c4c9cad99aebcdc4c4c9cad985c8c4c6">[email protected]</a>", image: "/profile/image/foobar1/foobar1.jpg", phoneNumber: "919999999"}

Despite having confirmed that profiles is not empty, the md-cards are not rendering. How do I proceed to dynamically generate cards based on the number of profiles and populate them with values from the profile objects?

Answer №1

If you want to update profiles dynamically in Angular, consider using a BehaviorSubject from rxjs and emitting the profiles from the response. Utilize the async pipe in your template to ensure that Angular's change detection captures the updates.

private readonly profiles$$ = new BehaviorSubject([]);
public readonly profiles$ = this.profiles$$.asObservable();

//  ...

search(term: string) {
  const apiUrl = `${this.apiRoot}?search=${term}&rows=10&callback=JSONP_CALLBACK`;
  return this.jsonp.request(apiUrl).map(res => {
    let results = res.json();
    this.profiles$$.next(results.profiles);
    return results;
  });
}

In your template:

<li *ngFor="let profile of profiles$ | async">
  <!--  ... -->
</li>

By the way, remember to remove the @Injectable decorator from the component as components should not be injectable.

Additionally, it is advisable to move the API call into a shared service for cleaner component logic that can be reused across other components. You may also want to explore the redux pattern by looking into @ngrx/store and @ngrx/effects for better state management and control over data handling with external APIs. More information can be found at the @ngrx/platform monorepo on GitHub.

Answer №2

Your query result is transformed into a map() and still provides Observable or promise. Therefore, it is essential to manage the asynchronous nature of the data received from the server.

Angular offers an async pipe that can be utilized in your template to indicate that whenever the data arrives, update my UI accordingly.

You can relocate your server request to an @Injectable() service that will return an Observable. Subsequently, store this Observable in your component variable and utilize the async pipe in your UI.

<ul>
    <li *ngFor="let profile of profiles | async">
      <md-card class="example-card">
        <md-card-header>

This approach works seamlessly with Observables and http calls in Angular API. As Angular loads, it completes the template binding before receiving data from the server, causing a delay in updating the UI. Handling this asynchronous behavior is crucial for proper functionality. Hope this explanation clarifies things for you :)

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

The service does not fall within the 'rootDir' directory in the Angular secondary module

Encountering an error while compiling an Angular library related to the rootDir of sub libraries library/services/src/public-api.ts:31:15 - error TS6059: File 'C:/libname/library/services/src/orders/orders.service.ts' is not under 'rootDir& ...

Highly Transferable Angular Modules for 'ng-cli'

I am managing a system with multiple Angular applications built using the ng-cli: FrontendLibs @company/ core/ src/ package.json index.ts main-app/ src/ package.json In this scenario, I have two Angular applications name ...

Can you provide any instances of Angular2 projects with intricate routing, specifically with version 2.0.0-rc.1?

Currently, I am in the process of building a web application with angular2 (2.0.0 rc 1) and encountering obstacles due to the insufficient documentation, especially when it comes to establishing intricate routing. Since version 2.0.0 was just released app ...

Issue with IE11 compatibility in Angular2 (AngularQuickStart version 2.4.0) due to syntax error

Encountering an error in the browser console when attempting to run my Angular2 app on IE11. The error "Недопустимый знак" translates to unacceptable symbol. https://i.stack.imgur.com/0mHBC.png Here is a snippet of my index.html: <!DO ...

Using TypeScript to wrap a class with a Proxy object

I've been working on a function that takes an API interface (I've provided a sample here) and creates a Proxy around it. This allows me to intercept calls to the API's methods, enabling logging, custom error handling, etc. I'm running i ...

Sending real-time data from the tRPC stream API in OpenAI to the React client

I have been exploring ways to integrate the openai-node package into my Next.js application. Due to the lengthy generation times of OpenAI completions, I am interested in utilizing streaming, which is typically not supported within the package (refer to he ...

Angular 5 is encountering an error with a recursive template, specifically a RangeError stating that the maximum call stack

Hey there, I'm currently utilizing Angular recursive template to represent arrays recursively. The code I've been following is provided in this link. My array is dynamic in nature. <ul> <ng-template #recursiveList let-list> ...

Is there a way to reveal only the version information from the package.json file in an Angular 17 project?

Is there a secure way to extract and display only the version from a package.json file on the UI of a web application without exposing the rest of its contents? I am currently using the following structure in my package.json: { "name": "exa ...

Implementing experimental decorators and type reconciliation in TypeScript - A step-by-step guide

My basic component includes the following code snippet: import * as React from 'react'; import { withRouter, RouteComponentProps } from 'react-router-dom'; export interface Props { }; @withRouter export default class Movies extends R ...

Setting the value of a custom component property dynamically after the component has been rendered

I'm currently developing an Angular application and have a specific requirement to work on. I am using a custom component with 3 inputs, and I want to bind this custom component tag in the HTML of my page. <my-column [setInfo]="info" [dis ...

How to choose a particular Excel spreadsheet in Angular before importing the file?

I am currently working on a new feature that allows users to choose a specific Excel worksheet from a dropdown list before importing a file. However, I am facing some difficulty in adding the worksheet names to the dropdown list. Right now, I have placehol ...

Creating a regular expression for validating phone numbers with a designated country code

Trying to create a regular expression for a specific country code and phone number format. const regexCountryCode = new RegExp('^\\+(48)[0-9]{9}$'); console.log( regexCountryCode.test(String(+48124223232)) ); My goal is to va ...

One of the essential components in Angular is currently absent

After integrating Angular4 with Visual Studio 2017 following the steps outlined in this article, I realized that my setup also involved using Nodejs 8.6.0 and npm 5.4.2 - which were the latest versions at the time. Despite having vs2017 generate a fold ...

Having issues with autocompletion in the input element of Angular 7 Material Design

My Angular 7 application includes a Material Design form with input text fields, and I have not implemented any autocomplete feature within the code. Despite deleting all navigation data from my Chrome browser, I am still experiencing autocomplete suggesti ...

The type 'undefined' cannot be assigned to a different type within the map() function, resulting in a loss of type information

I am facing an issue in my redux toolkit where an action is trying to set some state. Below is the relevant code snippet: interfaces export interface ProposalTag { id: number; name: string; hex: string; color: string; } export interface ProposalS ...

How can I transfer the document id from Angular Firestore to a different component?

I'm seeking assistance on how to achieve a specific task related to pulling data from Firestore in my Angular application and displaying it in a list. Everything is working smoothly, including retrieving the document ID. My goal is to have the retrie ...

Learn how to dynamically enable or disable the add and remove buttons in the PrimeNG PickList using Angular 2

I'm currently learning Angular 2 and I'm working on creating a dual list box using PrimeNG's pickList component (https://www.primefaces.org/primeng/#/picklist). Within the pickList, I have table data with 3 columns, along with ADD and REMO ...

What is the best way to switch routes in redux saga upon successful login?

Greetings! I'm a newcomer to React and I've been using React hooks and redux-saga for my project. I have a requirement where I need the router to navigate to /home upon successful login. I attempted to achieve this using connected-react-router an ...

The conventional method for including React import statements

I'm curious if there is a standard convention for writing import statements in React. For instance, I currently have the following: import React, { useState, FormEvent } from 'react'; import Avatar from '@material-ui/core/Avatar'; ...

"Production mode is experiencing a shortage of PrimeNG(Angular) modules, while they are readily accessible in development

I've been diligently working on an Angular application that heavily relies on PrimeNG as the UI component framework. Initially, I had no issues deploying my app with Angular version 9 and PrimeNG version 8. However, a while ago, I decided to upgrade t ...