0

I have an observable that contains some data.

I also have a method that gets 1 specific field:

getField(fieldName: string) {
 return this.response$.asObservable().
  pipe(
    map(data => data[fieldName]),
    take(1)
  )
} 

------------------------------------------------

getFirstNameGroup(): Observable<any> {
   return this.service.getField('first_name'); // returns current field's properties as an object
}

I want to pass not only one field name but many, something like this:

getFields(fieldNames: string[]) {
 return this.response$.asObservable().
  pipe(
    map(data => fieldNames.map(field => data[field])),
    take(1)
  )
}

------------------------------------------------

getPersonName(): Observable<any> {
    // returns an array of objects where indexes 0 and 1 are instead of first_name and last_name
    return this.service.getFields(['first_name', 'last_name']); 
}

I just can't figure out what should I change in map() in order to get an object that will be like (or something like this):

{
  first_name: {...},
  last_name: {...}
}

Thanks :)

desmondische
  • 186
  • 13

2 Answers2

1

Try this:

map(data => fieldNames.reduce((prev, curr) => ({...prev, [curr]: data[curr]}), {} as any)),

Explanation:

Let's say fieldNames array looks like this ['first_name', 'last_name', 'phone_no'] so now what happens in each iteration?

In each iteration we use the spread operator to merge previous value saved under prev with one new property.

#1 iteration

({ ...{}, 'first_name': data['first_name'] })

which equals to

{ 'first_name': {} }

prev is the empty {} passed as last parameter to the reduce function. [curr] syntax let us use dynamic keys in objects so this translates just to 'first_name' as this is the value of curr at this moment.

#2 iteration

({ ...{'first_name': {} }, 'last_name': data['last_name'] })

which equals to

{ 'first_name': {}, 'last_name': {} }

#3 iteration

({ ...{ 'first_name': {}, 'last_name': {} }, 'phone_no': data['phone_no'] })

which equals to

{ 'first_name': {}, 'last_name': {}, 'phone_no': {} }

With each iteration curr gets the next element of the fieldNames array and prev the last returned value from the reduce function.

Moreover for the reduce function the Advanced syntax of arrow function is used, which let us elegantly return a literal object.

For simplicity I assume that data is dictionary with a key of type string and value of type object. I put just empty objects as placeholders.

Lukasz Gawrys
  • 1,234
  • 2
  • 8
0

You can use object literal syntax. Like this:

map(data => ({
  first_name: data.fs,
  last_name: data.ls
}))

or if you prefer indexing fields on objects

map(data => ({
  first_name: data[fs]
  last_name: data[ls]
}))
Mrk Sef
  • 7,557
  • 1
  • 9
  • 21
  • I want this method to be generic. So I could pass different fields, i.e. email, phone etc. I don't want to specify properties. I want them to be created using fieldNames parameter – desmondische Dec 20 '21 at 12:27