3

I am attempting to write an Angular 6 service that connects to the DreamFactory API.

I have managed to extract json data from the "brand" table in a database that I have allowed DreamFactory to manage. I am able to send a get request to the API so there is no problems with comms. Below is a sample:

{
  "resource": [
    {
      "id": 1,
      "name": "Apple",
      "display_order": 1,
      "visible": true
    },
    {
      "id": 2,
      "name": "Dell",
      "display_order": 6,
      "visible": true
    },
    {
      "id": 3,
      "name": "HP",
      "display_order": 5,
      "visible": true
    },
    {
      "id": 4,
      "name": "HTC",
      "display_order": 4,
      "visible": true
    },
    {
      "id": 5,
      "name": "Samsung",
      "display_order": 2,
      "visible": true
    },
    {
      "id": 6,
      "name": "Sony",
      "display_order": 3,
      "visible": true
    }
  ]
}

I am struggling with the formatting of the data:

How do I map the fields in the "resource" response to a class I created in Angular? I have imported “brand.ts” in to “data.service.ts”. I have imported HTTPClient in all the correct places like “app.module.ts” and in “data.service.ts” and used it in constructor() {} etc.

'../models/brand.ts'

export class Brand{
    id: number;
    name: string;
    displayOrder: number;
    isVisible: boolean;
}

‘../services/data.service.ts’

...
    getBrands() {
        this.http.get(this.baseUrl + 'brand' + '?api_key=' + this.APP_API_KEY)
          .map((data: Response) => {
            return data;
          })
          .subscribe((data => {
            console.log(data);
            this.brands = data;
          })
          );
      }

...

By using the above code in the console log my data outputs like the following:

resource: (6) […]

0: Object { id: 1, name: "Apple", display_order: 1, … }

1: Object { id: 2, name: "Dell", display_order: 6, … }

2: Object { id: 3, name: "HP", display_order: 5, … }

3: Object { id: 4, name: "HTC", display_order: 4, … }

4: Object { id: 5, name: "Samsung", display_order: 2, … }

5: Object { id: 6, name: "Sony", display_order: 3, … }

length: 6 …

How do I modify my code to map the data to my class? For example the field “display_order” needs to map to my Angular class property “displayOrder” etc. Any help would be appreciated as I am a noob to Angular.

Jota.Toledo
  • 27,293
  • 11
  • 59
  • 73
  • Possible duplicate of [How to map JSON object to Typescript object using RxJS](https://stackoverflow.com/questions/46654601/how-to-map-json-object-to-typescript-object-using-rxjs) – Jota.Toledo Jun 01 '18 at 17:27
  • Have you tried something? Being a "noob" isnt a valid excuse IMO to justify your lack of self teaching – Jota.Toledo Jun 01 '18 at 17:31
  • @Jota, I have tried to self teach (my poor attempt above), but sometimes you turn to the internet (especially StackOverflow) to get pointed in the right direction when attempts to make inroads fail. An online training video on Udemy that I was watching was using the old HTTP Client examples and it also doesn't help when legacy AngularJS search results creep in when you turn to google for any Angular (2+) related research! I will not give up on learning Angular! Thanks for the info BTW – Research Stuff Jun 01 '18 at 18:29
  • Mate I Have updated my answer see if it helps you – Vikas Jun 01 '18 at 20:58
  • @Vikas - Cheers bud, I will attempt to implement the changes tomorrow :-) – Research Stuff Jun 02 '18 at 00:06

3 Answers3

0

Add a constructor to your class type like so:

export class Brand {
  id: number;
  name: string;
  displayOrder: number;
  isVisible: boolean;

  constructor(item) {
    this.id = item.id;
    this.displayOrder = item.display_order;
    // set rest of variables
  }
}

Then pipe the response and create a new Object that maps your fields to the correct fields like so:

  getBrands(url: string): Observable<Brand[]> {
    return this.http.get(url).pipe(map((data: any[]) => {
      const res: Brand[] = [];
      data.map((item) => {
        res.push(new Brand(item));
      });
      return res;
    }));
  }

I set this up as a return from the service, as you should return this Observable to the component code out of the service and then subscribe there. This will output an array of Brand with the fields mapped

The setting of fields in your constructor will let you set the field of displayOrder to the incoming data of display_order.

Hope this can be of help!

Nicholas Pesa
  • 2,156
  • 2
  • 24
  • 45
  • If you edit this to use strong types instead of none or any, you get my upvote – Jota.Toledo Jun 03 '18 at 13:50
  • Made some edits for the types. The data coming from the HTTP pipe.map is still any[] as an Interface would need to be made that aligns with DreamFactory response. – Nicholas Pesa Jun 04 '18 at 01:31
  • the constructor of your Brand class is still weakly typed, add an interface to define those values – Jota.Toledo Jun 04 '18 at 06:38
  • @Jota.Toledo thank you for the advice! My goal here is to answer the question above and I believe I have done so and want to do so like I have put in my answer above, so the user can make advancements to his code as he learns further. I want to help move the user in the right direction but not put code that may be misunderstood without proper knowledge of Angular. Thank you for considering upvoting, I take that as my answer has been helpful! – Nicholas Pesa Jun 04 '18 at 21:26
0

Thanks for the suggestions. It was the "resource" key in the JSON that needed consideration!

{
  "resource": [
    {
      "id": 1,
      "name": "Apple",
      "display_order": 1,
      "visible": true
    },
    {
      "id": 2,
      "name": "Dell",
      "display_order": 6,
      "visible": true
    },
    {
      "id": 3,
      "name": "HP",
      "display_order": 5,
      "visible": true
    },
    {
      "id": 4,
      "name": "HTC",
      "display_order": 4,
      "visible": true
    },
    {
      "id": 5,
      "name": "Samsung",
      "display_order": 2,
      "visible": true
    },
    {
      "id": 6,
      "name": "Sony",
      "display_order": 3,
      "visible": true
    }
  ]
}

I managed to succeed using the following:

brand.ts

export interface Brand {
  id: number;
  name: string;
  display_order: number;
  visible: boolean;
}

data.service.ts

  getBrands(): Observable<Brand[]> {
    return this.http.get<Brand[]>(this.baseUrl + 'brand' + '?api_key=' + this.APP_API_KEY)
    .pipe(
      map(res => res['resource'])
    );
  }
-2
this.http.get<Array<Brand>>('/whateverurl).subscribe( ...  

dont forget to import the Brand class/interface

EDIT : if its an array you need to <Array<Brand>>

Marouan
  • 217
  • 1
  • 8