1

I have searched and found some information here: Iterate array inside object Angular 6 but I cannot get it to work properly.

I have an API call and it returns an array of objects (DocumentHead):

enter image description here

Each of these has an object array called documents:

enter image description here

Each DocumentHead will always have an entry for documents so code below works (sort of)

<li *ngFor="let docHead of DocumentHead;">
  {{docHead.documents[0].id}}
</li>

(Code {{docHead.documents.id}} says it is undefined)

DocumentHead.documents[0].id will return at least 1 entry id for each of the 5 entries. What I want is that for each DocumentHead, it will list the id of each entry in documents I currently have this:

<li *ngFor="let docHead of DocumentHead;">
  <div *ngFor="let docs of docHead.documents[i]; let i = index; ">
    <h3> {{docs.category.name}} </h3>
  </div>
</li>

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

(It won’t allow “let docs of docHead.documents, gives error: Type DocumentsModel is not assignable to type (DocumentsModel & NgIterable) | undefined | null )

Tried code from Loop through array of JSON object with *ngFor (Angular 4)

<div *ngFor="let recipient of docHead.documents | keyvalue">
  {{recipient.key}} --> {{recipient.value}}
</div>

And getting this output

enter image description here

This is close to what I want. (In html component getting error: Argument type DocumentsModel is not assignable to parameter type {[p: string]: number | string | boolean …>)

How can I iterate over docHead.documents so that my list shows the id of all documents?

ETA Model and call

DocumentHeadModel:

export class DocumentHeadModel {
 id: string;
 documents: DocumentsModel;
}


export class DocumentsModel {
 id: string;
}

call:

getDocuments(id: any): Observable<DocumentHeadModel[]> {
   return this.http.get<DocumentHeadModel[]>(this.myURL?id=` + id);
 }
Siobhan Holubicka
  • 147
  • 1
  • 4
  • 17
  • `let docs of docHead.documents[i];` should be `let docs of docHead.documents` I think. You want to iterate through all the documents for each DocumentHead, not just one, right? – Jason Goemaat Nov 11 '21 at 14:27
  • It won’t allow “let docs of docHead.documents, gives error: Type DocumentsModel is not assignable to type (DocumentsModel & NgIterable) | undefined | null – Siobhan Holubicka Nov 11 '21 at 14:36
  • 1
    Do you have a typedef for your data? Can you include it? It looks to me like documents is an array, if you're defining it differently that could cause an error. – Jason Goemaat Nov 11 '21 at 14:38
  • @JasonGoemaat I have added my model and my api call – Siobhan Holubicka Nov 11 '21 at 14:53
  • So the field on `DocumentHeadModel` is called `documents`, but it's an object, not an array, and it represents one document? You need a `DocumentHeadModel` for each `DocumentModel` and there is only one document id per head? – D M Nov 11 '21 at 14:54
  • Should `DocumentsModel.id` be `string[]`? – D M Nov 11 '21 at 14:55
  • It would seem so. I have access to get and post calls, I don't control the information returned. Each DocumentHeadModel returns one or more documents. Should I change it to be an array in the model? – Siobhan Holubicka Nov 11 '21 at 14:58
  • 1
    Yes, if you're expecting more than one `DocumentModel` per head, then change `DocumentHeadModel.documents` to `DocumentModel[]`. If instead you're expecting one `DocumentModel` with many identifiers per head, then change `DocumentModel.id` to `string[]`. – D M Nov 11 '21 at 15:01
  • 1
    @DM I changed it and it works. Thank you. feel a bit stupid now. Will accept your answer – Siobhan Holubicka Nov 11 '21 at 15:02

1 Answers1

2

If you have:

const documentHeads = [
    { 
        id: 1, 
        documents: [
            { id: 101, category: { name: 'Astrophysics' }}
        ] 
    },
    { 
        id: 2, 
        documents: [
            { id: 201, category: { name: 'Literature' }},
            { id: 202, category: { name: 'Mathematics' }} 
        ]
    }
];

And you want:

-- 1
    -- 101
-- 2
    -- 201
    -- 202

You would use:

<ol>
    <li *ngFor="let head of documentHeads">
        <p>{{ head.id }}</p>
        <ol>
            <li *ngFor="let doc of head.documents">{{ doc.id }}</li>
        </ol>
    </li>
</ol>

If you want:

-- 101
-- 201
-- 202

You would use:

<ol>
    <ng-container *ngFor="let head of documentHead">
        <li *ngFor="let doc of head.documents">{{doc.id}}</li>
    </ng-container>
</ol>

Note that you want to use ng-container in the second case because you don't want to create an HTML element between the ol and li elements.

D M
  • 5,769
  • 4
  • 12
  • 27
  • It won’t allow “let docs of docHead.documents, gives error: Type DocumentsModel is not assignable to type (DocumentsModel & NgIterable) | undefined | null – Siobhan Holubicka Nov 11 '21 at 14:37
  • `docHead.documents` is not a simple object array? Your question says "Each of these has an object array called documents". Could you please clarify the structure of your API response object and its children? – D M Nov 11 '21 at 14:40