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

Resolve the conflict with the upstream dependency in Angular

I understand that the solution to this issue can be found on SOF, but utilizing --legacy-peer-deps or --force is not an option for me on my production server. I am eager to comprehend the root cause of this error and find a proper resolution. Upon install ...

What is the process to activate a function within a component once a service method has been run?

I'm currently working on a chart configuration using amCharts, where an eventListener is registered for the bullets. This event listener then triggers another function in my chart service. My goal is to activate a method in my component as soon as th ...

I am encountering an issue with retrieving JSON data within an ngrx effect

I've been struggling for the past two days trying to display local json data (posts) in my view (PostsComponent). I keep encountering this error message in the console: ERROR Error: Cannot find a differ supporting object '[object Object]' of ...

Is there a way to update the parent state from a child component in React when using Switch Route?

I have a page that features a control panel for modifying the content on display through Switch-Route. The code structure is as follows: <div className="controls"> some controls here </div> <Switch> <Route exact path=&apo ...

Running into issues with TypeScript in conjunction with Redux-Form and React-Redux connect

My excitement for TypeScript grew until I encountered some frustrating incompatibilities between Redux-Form and React-Redux. I am aiming to wrap a component decorated with reduxForm using the connect decorator from react-redux—this method has always bee ...

Unable to retrieve data following a promise in Ionic 3

Hello, I'm currently working on an Ionic application that needs to display data in a Form Group after retrieving it with a SOAP ReadData request. Although I call my function and try to display the data in the form, there seems to be an issue as the f ...

Issue encountered while attempting to utilize the useRef function on a webpage

Is it possible to use the useRef() and componentDidMount() in combination to automatically focus on an input field when a page loads? Below is the code snippet for the page: import React, { Component, useState, useEffect } from "react"; import st ...

Function input custom operator in RxJs

I am currently working on developing a custom rxjs operator. My previous custom operators, such as MonoTypeOperatorFunction or the regular Observable that accepts input like strings or numbers, have been successful. However, I am facing a challenge with cr ...

Leveraging Angular 4 for efficient integration and application of d3 and d3-cloud libraries along with their corresponding typings

My goal is to create a word cloud using d3 + d3-cloud in Angular CLI (Angular 4+) I installed both libraries and their typings using npm i: "dependencies": { "d3": "^4.10.2", "d3-cloud": "^1.2.4" }, "devDependencies": { "@types/d3": "^4.1 ...

The loading of npm installed Firebase in Angular4 is not successful

I am currently facing an issue while trying to integrate npm installed Firebase with my Angular4 application. I have successfully installed the latest version of Firebase (version 4.1.1) using npm and verified that the installation was successful. Below is ...

The request body doesn't meet the interface requirements, but it does not trigger an error response

I created a specific interface called NewTransactionPayload to ensure that only objects of this type are accepted in the request body. Strangely, TypeScript does not show any errors when I host the application. Why is that? // Sample interfaces interface ...

Jasmine: utilizing unit test to spy on the invocation of a nested function

When running unit tests for an Angular app, I need to spy on a function called func1 to check if it is being called. However, within func1 there is a call to func2 and I also want to spy on that to see if it is being called. How should I structure my unit ...

Separate configurations for Webpack (Client and Server) to run an Express app without serving HTML files

I am currently developing an application with a Node Backend and I am trying to bundle it with Webpack. Initially, I had a single Webpack configuration with target: node. However, I encountered issues compiling Websockets into the frontend bundle unless I ...

angular 2 : Unable to locate the variable named 'Response'

I encountered an issue while working on my angular 2 project: Error: Cannot find name 'Response'. The error seemed to originate from the following service: import { Injectable } from '@angular/core'; import { Http } from '@ang ...

Eliminate the routerLinkActive attribute that assigns two classes when the user switches to a different menu

As I develop a Web Application using Angular 6, I encounter an issue with implementing routerLink and routerLinkActive. While routerLink works properly, the routerLinkActive does not seem to function as expected. It retains the class within the tag even wh ...

Fixed headers remain in place as you scroll horizontally on a single table

Within my system, I have organized two tables: table one and table 2 are stacked on top of each other. I've managed to freeze the column headers so that they are displayed vertically, remaining static as users scroll horizontally. To achieve this effe ...

Styling multiple checkbox items in an Angular Material Autocomplete

Is there a way to adjust the height of autocomplete multiple checkbox items in Angular Material? I'd like it to look like this With a line item height of 18px But instead, it looks like this when using multiple checkboxes With a different checkbox ...

Issues with Angular2 causing function to not run as expected

After clicking a button to trigger createPlaylist(), the function fails to execute asd(). I attempted combining everything into one function, but still encountered the same issue. The console.log(resp) statement never logs anything. What could be causing ...

Issue [ERR_MODULE_NOT_FOUND]: The module 'buildapp' could not be located within buildserver.js

I am currently working on a node project using typescript. The project's structure is organized in the following way: --src |-- server.ts |-- app.ts --build |-- server.js |-- app.js In server.ts: import { app } from &q ...

Implementing Authorization keys in Angular's Swagger UI using code

I am currently in the process of integrating swagger ui into an Angular 7 application. Utilizing the npm package swagger-ui 3.37, the API documentation is structured with swagger 2.0. The integration works smoothly when authorization is not required within ...