从 API 响应动态创建 md-card [英] dynamically create md-card from API response

查看:21
本文介绍了从 API 响应动态创建 md-card的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在调用 API 并存储一堆用户配置文件,我希望能够为每个配置文件动态创建卡片(Angular Material Design md-card).返回的配置文件数量可能会有所不同,因此这需要是动态的.

这是我的组件文件,它发出 JSONP 请求并将配置文件存储在 profiles 变量中:

import {Component, Injectable, OnInit} from '@angular/core';从@angular/http"导入 {Jsonp};@成分({选择器:应用人员",templateUrl: './staff.component.html',styleUrls: ['./staff.component.css']})@Injectable()导出类 StaffComponent 实现 OnInit {公共搜索字段:字符串;apiRoot = 'this/is/my/api/url';公开结果:JSON;公开资料;构造函数(私有 jsonp:Jsonp){}ngOnInit() {}setSearchField(field: string){//忽略这个方法this.searchField = 字段;console.log('接收字段:' + this.searchField);}搜索(术语:字符串){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']; 返回 results.json(); });}}

这是上述组件的模板,我尝试使用 *ngFor 创建一个 md-card 列表:

<div class="row justify-content-center"><div class="col-md-auto"><ul><li *ngFor="let profile of profile"><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>部门</md-card-subtitle></md-card-header><img md-card-image src="../assets/image.png"><md-card-content><p>卡片的这一部分将包含有关搜索结果的信息.也可以附有附加信息,例如链接.</p></md-card-content><md-card-actions><button md-button>APPLY</button><button md-button>转到xyz</button></md-card-actions></md-card>

我的profiles数据是数组形式(假设数组长度不超过10),格式如下:

0: {fullName: "Foo Bar", emailAddress: "foobar@foobar.com", image: "/profile/image/foobar/foobar.jpg", phoneNumber: "99999999"},1: {fullName: "Foo Bar1", emailAddress: "foobar1@foobar.com", image: "/profile/image/foobar1/foobar1.jpg", phoneNumber: "919999999"}

但是,没有渲染md-card.我已经检查过 profiles 不是空的.如何根据配置文件的数量动态创建卡片并使用配置文件对象中的值填充内容?

解决方案

您可以尝试使用 rxjs 中的 BehaviorSubject 并从响应中发出配置文件.在您的模板中使用 async 管道.这将确保 angular 的变化检测会发现变化.

私有只读配置文件$$ = new BehaviorSubject([]);公共只读配置文件$ = this.profiles$$.asObservable();//...搜索(术语:字符串){const apiUrl = `${this.apiRoot}?search=${term}&rows=10&callback=JSONP_CALLBACK`;返回 this.jsonp.request(apiUrl).map(res => {让结果 = res.json();this.profiles$$.next(results.profiles);返回结果;});}

并在您的模板中:

  • <!-- ... -->
  • 顺便说一句:从组件中移除 @Injectable 装饰器,组件不应该是 injectable.

    注意:您真的应该考虑将 api 调用移动到共享服务中,这将使您的组件逻辑保持干净,并且您也可以在其他组件中使用它.您也可以了解 redux 模式",为此您可以查看 @ngrx/store@ngrx/effects.更多信息可以在 @ngrx/platform monorepo 中找到.它将让您对应用程序的状态拥有巨大的控制权,并且可以更轻松地管理您的数据并控制来自外部 API 的请求/响应.

    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: "foobar@foobar.com", image: "/profile/image/foobar/foobar.jpg", phoneNumber: "99999999"},
    
    1: {fullName: "Foo Bar1", emailAddress: "foobar1@foobar.com", 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?

    解决方案

    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.

    这篇关于从 API 响应动态创建 md-card的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    相关文章
    其他开发最新文章
    热门教程
    热门工具
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆