【问题标题】:Angular / Firebase - How to use *ngFor on objectAngular / Firebase - 如何在对象上使用 *ngFor
【发布时间】:2018-02-03 10:02:12
【问题描述】:

我正在使用什么

  • 角度
  • Firebase

我有什么

  • 显示“问题”详细信息的组件

  • 在问题中,我有另一个名为“images”的节点

  • 在图像节点内部,我将拥有更多属性,例如“image_title”

我正在努力实现的目标

  • 我的问题组件可以显示与问题相关的所有数据

  • 但是,一个问题可能在图像节点下有多个图像

  • 我还想循环遍历图像节点并显示所有 'image_title' 属性

错误 我收到以下代码错误:

错误错误:找不到类型为“object”的不同支持对象“[object Object]”。 NgFor 只支持绑定到 Arrays 等 Iterables。

问题

  • 这怎么可能?

问题列表解决程序

resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<any> {
        return Observable.create(observer => {

            this.authService.user
                .first()
                .subscribe(user => {

                    const projectId = route.params['projectId'];
                    const issueId = route.params['issueId'];

                    this.database.object(`/issue/${projectId}/${issueId}`)
                        .first()
                        .subscribe(issue => {
                            observer.next(issue);
                            observer.complete();
                        });
                });
        });
    }

问题组件 imagesToDisplay 是:

'imagesToDisplay: FirebaseListObservable;'

    this.activatedRoute.data
      .subscribe((
        data: { issueData: any, issueImageData: any }) => {
        this.issueToDisplay = data.issueData;
        this.imagesToDisplay =  data.issueData.images;
        console.log(this.imagesToDisplay);
      });

发布组件 HTML

HTML 中有一条注释,我试图在其中循环浏览图像。

<ul class="vs__details__ul">

  <li class="vs__details__li" *ngIf="issueToDisplay.issue_title">
    <div class="vs__label"> Issue Title </div>
    <div class="vs__data"> {{ issueToDisplay.issue_title }} </div>
  </li>

  <li class="vs__details__li" *ngIf="issueToDisplay.issue_comments">
    <div class="vs__label"> Issue Comments </div>
    <div class="vs__data"> {{ issueToDisplay.issue_comments }} </div>
  </li>

  <li class="vs__details__li">
    <div class="vs__label"> Images </div>
    <!-- LOOP THROUGH IMAGES HERE -->
    <div class="issue__images" *ngFor="let image of imagesToDisplay">

    <div class="vs__data"> {{ image.image_title }}</div>
    </div>
  </li>

</ul>

来自 Firebase 的 JSON 结构

控制台 -(来自组件中的 console.log)

【问题讨论】:

    标签: angular firebase firebase-realtime-database


    【解决方案1】:

    创建一个自定义管道keys 以获取keysObject 列表

    // pipes.ts
    import { Pipe, PipeTransform } from '@angular/core';
    
    
    @Pipe({ name: 'keys' })
    export class KeysPipe implements PipeTransform {
        transform(value, args: string[]): any {
            if(value instanceof Object) return Object.keys(value);
            else return [];
        }
    }
    

    app.module.ts 中包含新的自定义管道

    // app.module.ts
    import { KeysPipe } from './pipes.ts;
    
    @NgModule({
     declarations: [ KeysPipe ]
    

    并用它来迭代*ngFor中的Object

    <div *ngFor="let img of images | keys">
       <p>{{x[img]['title']}}</p>
    </div>
    

    图像对象:

    images = {
       'img1': {'title': 'Title1'},
       'img2': {'title': 'Title2'},
       'img3': {'title': 'Title3'},
       'img4': {'title': 'Title4'}
    }
    

    【讨论】:

    • 谢谢拉杰兹。我以前没用过管道。如何将我的数据与管道关联?
    • 好主意,只返回一个对象数组而不是键。
    • 更新了答案@ETX。
    • 谢谢拉杰兹。我也试过你的方法。似乎很接近。我添加了

      {{['image_title']}}

    • 它带回了两个项目......有! (好的开始)。但它只显示字符串“image_title”(如您所料)我如何获取实际值?
    【解决方案2】:

    问题是您需要将图像(这是一个对象文字)转换为可迭代的,以便*ngFor 识别它。您可以将所有图像添加到一个数组中,然后再将其传递给imagesToDisplay

    const images = [];
    for (const image of Object.keys(data.issueData.images)) {
     images.push(data.issueData.images[image]);
    }
    this.imagesToDisplay = images;
    

    为你创建一个函数:

    interface Image {
      image_title: string;
    }
    // ...
    
    function getIterableImages(images: any): Image[] {
      const arrayImages = [];
    
      // returns empty array if input is not defined
      if (images == undefined) return arrayImages;
    
      // returns an array of first level elements inside of object
      for (const key of Object.keys(images)) {
        if (images[key] != undefined) {
          arrayImages.push(images[key]);
        }
      }
      return arrayImages;
    }
    // ...
    
    this.activatedRoute.data
          .subscribe((
            data: { issueData: any, issueImageData: any }) => {
            this.issueToDisplay = data.issueData;
            this.imagesToDisplay = getIterableImages(data.issueData.images);
            console.log(this.imagesToDisplay);
          });
    

    【讨论】:

    • 感谢 Praiser - 选择第二个选项时出现以下错误:类型 'Map' 不可分配给类型 'any[]'。 'Map' 类型中缺少属性 'length'。
    • Opps,所以*ngFor 还不支持Map,它必须是数组
    • 我更新了我的答案!我不知道ngFor不支持Maps,那是因为ngFor需要元素的长度。
    • 啊太棒了!这太近了!这适用于在图像节点下具有数据的项目。如果没有引发以下错误:“ERROR TypeError: Cannot convert undefined or null to object” - 可能是 HTML 中的 *ngIf 检查?
    • 或者检查返回值是否大于1,如果是,调用'getIterableImages'函数?
    猜你喜欢
    • 2019-07-20
    • 2018-07-08
    • 2021-03-28
    • 2017-11-11
    • 2018-01-30
    • 1970-01-01
    • 1970-01-01
    • 2016-12-29
    • 2020-08-25
    相关资源
    最近更新 更多