Johna
Johna

Reputation: 1894

Using RxJs map to convert one type of array to another type of array

In my Angular application I use HttpClient to get json data from server. However, I need to do some conversion to the returned data at the client-side.

So I try to convert an array of Type A returned from the server to an array of Type B with the following code snippet.

this.http.get<any[]>(this.env.accounts.url.accountTypes).pipe(map(e => {
    console.log(e); // print the retuned array not a single item
    return {'label': e.name, 'value': e.id}
  }
)).subscribe(data => {
  this.accountTypes = data;
  console.log(this.accountTypes); // prints {label: undefined, value: undefined}
});

I must be doing this wrong, but I cannot figure out what is wrong here.

The server returns an array like:

[
  {name: "Name 1", id: 1},
  {name: "Name 2", id: 2},
  {name: "Name 3", id: 3},
]

And I need to convert it into the following format

[
  {label: "Name 1", value: 1},
  {label: "Name 2", value: 2},
  {label: "Name 3", value: 3},
]

Can somebody please point out what is wrong in my code and how to fix it.

Upvotes: 5

Views: 6759

Answers (4)

wentjun
wentjun

Reputation: 42586

You are confusing Array.map, with RxJS's map operator.

As stated on the RxJS documentation for the map operator, the purpose of Map is to

Apply projection with each value from source.

What you can do instead, is this:

this.http.get<any[]>(this.env.accounts.url.accountTypes)
  .pipe(
    map(res => {
      // insert logic 
      const data = res.map(obj => ({
        label: obj.name,
        value: obj.id
      }));
      return data;
    })
  )).subscribe(data => {
    this.accountTypes = data;
    console.log(this.accountTypes); // prints {label: undefined, value: undefined}
  });

Upvotes: 9

i.karayel
i.karayel

Reputation: 4885

Of course there are many solutions but Model Adapter can be a generic solution.

// app/core/adapter.ts
export interface Adapter<T> {
    adapt(item: any): T;
}
export class AccountType {
//.....
}
export class AccountAdapter implements Adapter<AccountType> {

    adapt(item: any): AccountType {
        return new AccountType(
            item.id,
          --  item.name,
          ++  item.value,
        );
    }
}


export class AccountService {
    private baseUrl = 'http://api.*';
    constructor(
        private http: HttpClient,
        private adapter: AccountAdapter,
    ) { }

    list(): Observable<AccountType[]> {
        const url = `${this.baseUrl}/`;
        return this.http.get(url).pipe(
            // Adapt each item in the raw data array
            map((data: any[]) => data.map(item => this.adapter.adapt(item))),
        );
    }
}

this example may help more

Upvotes: 0

Nicholas K
Nicholas K

Reputation: 15443

You can transform the data using the map operator:

var result = [];
x.map(e => {
  const obj = {};
  obj['label'] = e.name;
  obj['value'] = e.id;
  result.push(obj);
})

Upvotes: 2

MoxxiManagarm
MoxxiManagarm

Reputation: 9134

As mentioned in the comment please also map the array content

return e.map(entry => {'label': entry.name, 'value': entry.id});

Upvotes: 4

Related Questions