Does NgFor support Arrays containing one Object

2019-09-16 06:25发布

问题:

I am trying to dynamically create some HTML using Angular2's NgFor.

The problem I seem to be having is that whenever I have an array containing one object.

The error I am getting is as follows:

"Cannot find a differ supporting object '[object Object]' of type 'object'. NgFor only supports binding to Iterables such as Arrays".

Below is a typical JSON Object (which is one of many Objects in an array) which I am referring to...

{
        "id": "B5EE385D-1D6A-335A-1E94-2F857428A6FB",
        "type": "workBench",
        "label": "By Collection",
        "activeArea": "SELECTIONBYCOLLECTION",
        "alpha": "100",
        "backgroundAlpha": "100",
        "backgroundColor": "0xFFFFFF",
        "bottomArray": "1,3,2,3,4,4,4,4,4",
        "color": "0x2d89ef",
        "columnCount": "15",
        "description": "Part of the Selection Project",
        "enabled": "true",
        "fCode": "f230",
        "gap": "5",
        "icon": "assets\\Slim4WebMetroIcons\\Software Icons\\SELECTION.png",
        "layout": "cell",
        "leftArray": "5,1,5,5,5,2,3,4,1",
        "numCols": "5",
        "numRows": "4",
        "padding": "5",
        "percentHeight": "100",
        "percentWidth": "100",
        "postTitleContentToApplication": "true",
        "requestDataOnNavTo": "0",
        "rightArray": "5,4,5,5,5,2,3,4,1",
        "rowHeight": "250",
        "rowScaleType": "fitScreen",
        "selectedIndex": "0",
        "titleVisible": "true",
        "topArray": "1,1,2,3,4,4,4,4,4",
        "topContentAreaVisible": "true",
        "visible": "1",
        "children": {
          "child": [
            {
              "id": "D5009DBB-B35D-F358-F0D7-447B6EA40732",
              "expand": "1"
            },
            {
              "id": "87D46DA2-044E-65A6-7CCD-3BA13ECSCDBP",
              "expand": "1"
            },
            {
              "id": "F2D16F8F-EE8E-1BF6-C1E8-447B901BB86C",
              "expand": "1"
            },
            {
              "id": "41EE9C5A-E789-E2BF-7DB1-447B846C2A3B",
              "expand": "1"
            },
            {
              "id": "3BB46EBF-5E7B-8FA2-3080-441DBB9D20DF",
              "expand": "1"
            },
            {
              "id": "260F2FD7-27AD-620A-ADD3-441DC4DAA3F7",
              "expand": "1"
            },
            {
              "id": "74E494A2-E8E1-5166-EA4A-441DCDBC2D20",
              "expand": "1"
            },
            {
              "id": "602FBE66-7552-8996-4873-441DE833ECCC",
              "expand": "1"
            },
            {
              "id": "382CA1C5-AD17-BDAA-75DB-441DDD55CC72",
              "expand": "1"
            }
          ]
        },
        "sessionVars": {
          "sessionVar": { "name": "activeArea" }
        },
        "dataObjects": {
          "dataObject": {
            "id": "SelectionCollectionButtons",
            "type": "get"
          }
        },
        "topContent": {
          "child": { "id": "048A9A5E-A1A8-6DFA-F2E2-87568F67C5C3" }
        },
        "leftContent": {
          "width": "180",
          "visible": "1",
          "static": "false",
          "open": "true",
          "child": { "id": "6848C68A-0FA6-ABCD-8057-77A1B95121FA" }
        }
      },

This object renders correctly. Its first child that it refers to is below:

{
        "id": "D5009DBB-B35D-F358-F0D7-447B6EA40732",
        "type": "panel",
        "label": "Availability",
        "backgroundAlpha": "100",
        "backgroundColor": "0xFFFFFF",
        "cellAllocation": "5",
        "columnCount": "1",
        "description": "Panel displaying ONLY Availability Pod (Gauge)",
        "enabled": "1",
        "expand": "1",
        "fCode": "f2000",
        "layout": "vertical",
        "minWidth": "0",
        "padding": "0",
        "percentWidth": "100",
        "rowHeight": "250",
        "rowScaleType": "definedRowHeight",
        "visible": "1",
        "children": {
          "child": { "id": "8838E161-4DC2-EFA2-6971-44B04077DFA2" }
        }
      }

This Object has only one child and here is where the problem lies...

I am using the same script in each component to render the children; The script in the first instance works correctly as there is more than one child, however in the second instance, it crashes out with the error mentioned above.

The script I am using for the creation of children for both instances is as follows:

<p-panel header="{{control.label}}" >

    <ul *ngFor="let child of childRefs">

       <container-panel [controlRef]="child.id"></container-panel>

   </ul>

</p-panel>

And the associated ts file is as follows:

import {Component}      from '@angular/core';
import {OnInit}         from '@angular/core';
import {Input}          from '@angular/core';

import {Panel}          from 'primeng/primeng';

import {Control }           from '../services/service.controls';
import {ControlRef }        from '../services/service.controls';
import {ControlsService }   from '../services/service.controls';


import {PodContainer}  from './container.pod'

@Component({
    templateUrl : 'app/containers/container.panel.html',
    selector    : 'container-panel',
    directives  : [Panel,PodContainer],
    providers   : [ControlsService] 
})

export class PanelContainer implements OnInit  {


    private controls: Control[];

    @Input() private controlRef:string = ""








    private controlData:Control

    private childRefs:ControlRef[]


    constructor(private controlsService:ControlsService) { }

    ngOnInit() 
    {
        this.control   = this.controlsService.getControlByID(this.controlRef); 
        this.childRefs = this.control.children.child;
    }

    toControlRefs(val) {
        var ploop:childRefs = [val]
        return ploop 
    }


}

How do I get this script to work with Objects that contain only one child reference?

回答1:

I would test if the property is an array or not and transform it accordingly:

ngOnInit() {
  this.control   = this.controlsService.getControlByID(this.controlRef); 
  this.childRefs = this.control.children.child;
  this.childRefs = Array.isArray(this.childRefs)
          ? this.childRefs : [ this.childRefs ];
}

If you don't use such code in the component class you could implement a custom pipe for this:

@Pipe({
  name: 'arrayify'
})
export class ArrayifyPipe {
  transform(val) {
    return Array.isArray(val)
          ? val : [ val ];
  }
}

and use the pipe this way:

<p-panel header="{{control.label}}" >
  <ul *ngFor="let child of childRefs | arrayify">
    <container-panel [controlRef]="child.id"></container-panel>
  </ul>
</p-panel>


标签: angular ngfor