Using Object.assign with Observable Array - arrays

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.

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.

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

Related

Subscribe to an observable and put values into an array

I'm new in angular and I need some help.
I have an observable getting users of type User[]
User: [
id: string,
name: string
]
and I have another array Ids of type string getting the ids of the selected users from a mat-select
Ids = this.Form.controls['users'].value
what I need right now is to subscribe to users$ observable, and get only the users that they have an id in Ids
const selectedUsers = ids.forEach(id =>this.usersSub$.value.filter((user) => user.userId === id))
something like the above but it is not really the right thing to do because it returns undefined . I'm wondering how should I properly get my selectedUsers array.
You use combineLatest to merge both observables and map all elements to accomplish it.
First, Create an observable with ids.
selectedIds$ = of([1, 3]);
players$ = of([
{ id: 1, name: 'lebron' },
{ id: 2, name: 'irving' },
{ id: 3, name: 'love' },
]);
Next, combine both observables, using the combineLatest operator, and return the players using the map to iterate over the response from the combineLast, use the filter and find to match the playerid with the ids from the selectedIds array.
const seletedUsers$ = combineLatest([this.selectedIds$,
this.players$])
.pipe(
map(([ids, players]) => {
return players.filter((p) => ids.find((id) => id === p.id));
})
)
.subscribe((v) => {
console.log(v);
});
https://rxjs.dev/api/index/function/combineLatest
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter

react native turn object array into string array

I am searching for a while now, how I could achieve to turn objects arrays into an array with only values. For example, I have an array with several Restaurants and within these restaurants there is a key named category. Category could have multiple values like Sushi, Chinese, asian. I would like to go trough all object and reduce my array from:
[{
id: '1',
title: 'Italian Dream',
category: 'Pizza, Pasta, Snack',
opening_hours: '08:00-24:00',
},
{
id: '2',
title: 'Turkish Man',
category: 'Döner, Pizza, Lahmacun',
opening_hours: '08:00-24:00',
}]
to
[ Pasta, Snack, Döner, Pizza, Lahmacun]
Would be glad if anybody could give me any advice.
Cheers
Since category is a string and not an array of strings, we need to .split(', ')
Since we have multiple categories per data item, we can use .flatMap to "combine" or flatten that what would have been an array of arrays
We can use new Set(...) to get a unique list of string values
And finally use Array.from(...) to convert the Set to an Array.
const data = [{
id: '1',
title: 'Italian Dream',
category: 'Pizza, Pasta, Snack',
opening_hours: '08:00-24:00',
},
{
id: '2',
title: 'Turkish Man',
category: 'Döner, Pizza, Lahmacun',
opening_hours: '08:00-24:00',
}
]
const categories = Array.from(new Set(data.flatMap(x => x.category.split(', '))))
console.log(categories)
You can loop your array and use split function to extract categories from your string.
let newArray = [];
oldArray.forEach(restaurant => {
newArray.push(...restaurant.category.split(', '));
});
// Here newArray contains categories with duplicate values
// You can use Set to avoid duplicate values.
newArray = [...new Set(newArray)];

Adding data to complex state in react reducer

I have a react reducer that manages the following kind of state
const exampleState: INote[][] = [
[
{ x: 3, y: 5, value: '4' },
{ x: 3, y: 6, value: '4' },
],
[
{ x: 7, y: 3, value: '4' },
{ x: 8, y: 5, value: '7' },
{ x: 8, y: 5, value: '6' }
],
];
So a 2D array that contains arrays of a specific type of object. For some reason I can't figure out how to update this kind of state. I want to specifically be able to add a new instance (without mutating original state) of INote to a specific nested array. How can I achieve this? The index of the array I need to add the object to is in my reducers action object
Well, the obvious ways would be to update this state immutably, for instance, let's say I have a ADD_NOTE action, it could look something like that:
{type: "ADD_NOTE", payload: { item: INote, index: number }}
And then, an example return statement of the reducer for this action would be:
return state.map((arr, i) => i === index ? [...arr, item] : arr)
This will update the array, and will add item to the end of the array with the provided action index.
Another solution that might make your life easier is to use help libraries such as https://github.com/kolodny/immutability-helper or https://github.com/immerjs/immer
You need to use an array of objects instead of array of arrays so you can add an identifier such as an id to each object so you can update that specific object based on its id

Updating / inserting a nested object React / Redux [duplicate]

This question already has an answer here:
Update a nested state in redux
(1 answer)
Closed 5 years ago.
I have a JSON object in an array in my Redux store
editor: [] 1 item
0: {} 1 key
flow {} 3 keys
id: "1234"
name: "qaz"
tasks: [] 5 items
What is the best way to update or insert a new tasks array
My actions is
export function insertTasks(tasks) {
return {
type: 'INSERT_TASKS',
tasks
};
}
And the Reducer is
case 'INSERT_TASKS':
state[0].flow.tasks = [];
state[0].flow.tasks = action.tasks;
return state;
I'm passing it the action.type and action tasks correctly and I appear to be updating the tasks array inside my object. But this reducer code just doesn't feel correct.
When I add a completely new flow my reducer is
case 'ADD_FLOW':
state = [];
return [
...state, {
// index: 1,
flow : action.flow
}
]
which feels much better.
So I suppose I looking for the best way to access deep arrays in Redux .
You can continue using the spread syntax as deep as you want. For example given this:
var o = {
foo: bar,
baz: {
id: 1,
title: 'title',
description: 'description'
},
bang: [1, 2, 3]
};
then returning this:
return {
...o,
baz: {
...o.baz,
description: 'new description'
},
bang: [...o.bang, 4, 5]
};
will result in this:
{
foo: bar,
baz: {
id: 1,
title: 'title',
description: 'new description'
},
bang: [1, 2, 3, 4, 5]
}
You want to avoid reassigning or mutating anything in your reducers. To achieve this, assuming you only ever have a single item in your state array, you could do something like:
case 'INSERT_TASKS':
return [{
...state[0],
tasks: actions.tasks,
}];
What the spread (...) operator is doing here is taking all of the keys from state[0] and creating a NEW object with all the same keys currently in state[0] after which we are replacing the tasks key with the new tasks array.

AngularJS filter by id returns multiple entrys

i had an array like this:
arr = [
{ID: 502, Description: 'aaa', code: 1122},
{ID: 2, Description: 'bbb', code: 2211},
{ID: 700, Description: 'ccc', code: 2222}
];
when i try to filter the ID I get all occurences of the specific number:
$(filter)('filter')( arr, { ID: 2 } )[0]
returns entry one ID: 502 but it should return the entry with ID: 2
Where is my fault?
According to the docs when used with an object it will match the element if it contains the value.
A pattern object can be used to filter specific properties on objects contained by array. For example {name:"M", phone:"1"} predicate will return an array of items which have property name containing "M" and property phone containing "1".
There is a second option comparator passing true will cause it to perform a strict equality meaning it should only return exact matches.
$filter('filter')( arr, { ID: 2 }, true);
Fiddle: https://jsfiddle.net/enxbpjg0/
You could use a function instead of the object. So...
$filter('filter')(arr, function(value) {
return value.ID === 2;
});

Resources