2
votes

I'm using Object.assign to add an attribute to each element of an Observable Array

Struggling figuring out the right operators to add an attribute to each object of the array. For example, in this case the name field was used inappropriately for grade.

Example:

let x = Observable.of({id: 1, name: first grader}, {id: 2, name: second grader})

// current solution using flatmap and then re-configuring as array
x
.flatMap( res => res.map( student => Object.assign({}, student, {grade: student.name})))
.toArray()

The above example works, but seems strange...as I'm flatmapping and then re-constituting the array. Is there a better operator/ approach to reduce the steps?

If I just use Object.assign on the initial observable I get: Object {0: Object, 1: Object}, which is an object of objects rather than an array of objects.

2

2 Answers

3
votes

The above example works, but seems strange...as I'm flatmapping and then re-constituting the array. Is there a better operator/ approach to reduce the steps?

If your data is already available as an array then you can mutate the complete array yourself:

Rx.Observable.of([{id: 1, name: 'first grader'}, {id: 2, name: 'second grader'}])
  .map(students => {
    // note - this map below is Array.prototype.map, not Rx
    return students.map(student => Object.assign({}, student, {grade: student.name}));
  })
  .subscribe(x => console.log(x));

But Rx really shines when your data is received async:

Rx.Observable.from([{id: 1, name: 'first grader'}, {id: 2, name: 'second grader'}]) /* stream of future student data elements */
  .map(student => Object.assign({}, student, {grade: student.name}))
  .toArray() // combine your complete stream when completed into a single array emission
  .subscribe(x => console.log(x));

The toArray() is a utility function to wait for completion and then return all emitted elements inside an array as the first (and final) emission.

1
votes

If you run your code as it is it will fail. Because if you pass multiple objects to Observable.of it will push them into stream one by one.

So I assume what you meant is

    Rx.Observable.of([{id: 1, name: 'first grader'}, {id: 2, name: 'second grader'}])

note the square brackets.

To achieve what you want you can use map operator:

    Rx.Observable.of([{id: 1, name: 'first grader'}, {id: 2, name: 'second grader'}])
      .map(res => res.map( student => Object.assign({}, student, {grade: student.name})))
      .subscribe(x => console.log(x));

See jsBin