Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

dynamically create md-card from API response

I'm making an API call and storing a bunch of user profiles, and I want to be able to dynamically create cards (Angular Material Design md-card) for each profile. The number of profiles returned can vary, so this needs to be dynamic.

This is my component file which makes the JSONP request and stores 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;
  apiRoot = '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.apiRoot}?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 for the above component, where I'm trying 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>

My profiles data is in the form of an array (assume that the array doesn't exceed a length of 10) and takes the following form:

0: {fullName: "Foo Bar", emailAddress: "[email protected]", image: "/profile/image/foobar/foobar.jpg", phoneNumber: "99999999"},

1: {fullName: "Foo Bar1", emailAddress: "[email protected]", image: "/profile/image/foobar1/foobar1.jpg", phoneNumber: "919999999"}

However, there are no md-cards being rendered. I have checked that profiles isn't empty. How do I dynamically create cards based on the number of profiles and populate the content with values from the profile objects?

like image 738
bawse Avatar asked Sep 05 '17 01:09

bawse


1 Answers

You could try to use a BehaviorSubject from rxjs and emit the profiles from the response. In your template make use of the async pipe. This would make sure that angular's change detection would pick up the changes.

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;
  });
}

and in your template:

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

Btw: Remove the @Injectable decorator from the component, components shouldn't be injectable.

Note: You should really consider moving the api call into a shared service, this would keep your component's logic clean and you could use it in other components too. Also you could inform yourself about the redux "pattern", for this you can look into @ngrx/store and @ngrx/effects. More information can be found at the @ngrx/platform monorepo. It will give you huge control about your application's state and it's easier to manage your data and control requests/responses from an external APIs.

like image 89
cyr_x Avatar answered Oct 10 '22 07:10

cyr_x