0

The error I get:

core.js:6260 ERROR Error: Cannot find a differ supporting object '[object Object]' of type 'object'. NgFor only supports binding to Iterables such as Arrays.

at NgForOf.ngDoCheck (common.js:4406)
at callHook (core.js:4762)
at callHooks (core.js:4722)
at executeCheckHooks (core.js:4642)
at refreshView (core.js:11979)
at refreshComponent (core.js:13449)
at refreshChildComponents (core.js:11689)
at refreshView (core.js:12024)
at refreshComponent (core.js:13449)
at refreshChildComponents (core.js:11689)

The code below works if I have more then one object. When the data is as shown below, and from that, I understand that something is wrong with array or object but I am unable to figure it out. So when I have 2 objects I get the data in the dropdown, but when it is one I get the error mentioned above.

[
{..},
{..}
]

My data Looks like this:

{
"details_id": 218,
"master_code": 218,
"MstCode": null,
"start_date": "2020-02-29T00:00:00",
"end_date": "2020-02-29T00:00:00",
"canceled": "False   ",
"data_archived": null,
"last_updated_on": "2020-02-28 11:37:08",
"last_updated_by": null
}

My http get request code is as below:

this.http.get(this.apiBaseUrl+"ProgramDets/"+id).toPromise().then(res => this.Details = res as TrDetails);

My model code:

export class TrDetails {
    details_id: number;
    master_code: number;
    MstCode: number;
    start_date: Date;
    end_date: Date;
    canceled: string;
    data_archived: string;
    last_updated_on: Date;
    last_updated_by: string;
}

My service code:

apiBaseUrl = "http://localhost:2676/api/";
Details : TrainingDetails;

GetDetails(id){
    this.http.get(this.apiBaseUrl+"ProgramDets/"+id).toPromise().then(res => 
    this.Details = res as TrDetails);
  }

My dropdown code:

<option *ngFor="let data of service.Details" [value]="data.start_date">{{data.program_start_date}}</option>
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Mubeen
  • 88
  • 8

3 Answers3

1

I think what you need to is this:

GetDetails(id){
    this.http.get(this.apiBaseUrl+"ProgramDets/"+id).toPromise().then(res => 
    this.Details = res.json() as TrDetails);
  }

Updating the answer after some discussion:

If res was coming an object, you needed to convert this into an array, else if it's an array assign as it is. Also needed to catch if there's an error :

GetDetails(id){
    this.http.get(this.apiBaseUrl+"ProgramDets/"+id).toPromise().then(res =>
    if(Array.isArray(res)){
        this.Details = res;
    }else{
        this.Details = [res] as any //change any to your type that matches
    }
  }).catch(err => console.log(err));
}
ABGR
  • 4,631
  • 4
  • 27
  • 49
  • when I tried this I get an error. `Property json doesn't exist on type object` – Mubeen May 31 '20 at 07:12
  • Ok so it's clear now, `res ` is an object and not an array. So `ngFor` wont work in that case. Try putting `*ngIf* to check it;s an array first – ABGR May 31 '20 at 07:13
  • print the data with `console.log()`. Accordingly you can parse with `JSON.parse(res)` But first, we need to know what `res` is printing. – ABGR May 31 '20 at 07:16
  • Btw did you try `res.json() as any` instead of `TrDetails ` – ABGR May 31 '20 at 07:16
  • how to check if the object is an array or object using `ngIf`? – Mubeen May 31 '20 at 07:18
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/215016/discussion-between-rahul-dwivedi-and-p-mubeen). – ABGR May 31 '20 at 07:19
  • Yes I did try `res.json()` but it gives an error that `json cannot be applied on type object` – Mubeen May 31 '20 at 07:19
1

service.Details should be an array for *ngFor to work, it seems like the value of service.Details is an object here and hence you getting the error.

Ideally you should not subscribe within your service method, you should just return the observable from your service and subscribe it inside the component.

I recommend you to change your service method to this

 getDetails(id){
    return this.http.get(this.apiBaseUrl+"ProgramDets/"+id);
 }

And inside your component wherever you are calling getDetails method you can do this

this.details = this.service.getDetails(id).pipe(map(res => [res]))

Then in your html you can simply use your async operator to subscribe.I would suggest to use observable pattern instead of promise pattern, this will make your code look more clean

<option *ngFor="let data of (details | async)" [value]="data.start_date">{{data.program_start_date}}</option>
Shijil Narayanan
  • 1,011
  • 8
  • 21
  • yes, I figured that out but I don't know how to get the data. – Mubeen May 31 '20 at 07:13
  • You dont have to follow a promise pattern when you work with angular, angular gels well with observable pattern so you should follow that I would suggest, I have updated the ans, please check. – Shijil Narayanan May 31 '20 at 07:20
  • ok so just try this: `res => [res] || [];`, Thank you for the help but this solution worked and it was provided by @RahulDwivedi – Mubeen May 31 '20 at 07:31
1

If your logic is working when the response is an array, you just need to add any object response to an empty array before using it. Try changing your GetDetails method body to below

this.http.get(this.apiBaseUrl+"ProgramDets/"+id).toPromise().then((res: TrDetails | TrDetails[]) => this.Details = Array.isArray(res) ? res : [res]);
Kaustubh Badrike
  • 580
  • 2
  • 15