How to setState for nested array of object in react? - javascript

This is the object, lets say I'm gonna add something inside list: [], how can I do that? I know like we can do it using the prevList callback but I'm kind of confused to map through it.
const [boardlist, setBoardlist] = useState([
{
id: 1,
boardName: "home work",
data: [
{
id: 1,
header: "Stuff to do",
list: [
{
id: 1,
taskTitle: "working from home",
},
],
},
{
id: 2,
header: "In Progress",
list: [],
},
{
id: 3,
header: "Done",
list: [],
},
],
},
]);

What about make a copy of the state and just push using the bracket notation and dot notation to reach the element that you need to change?
const boardlistCopy = JSON.parse(JSON.stringify(boardlist));
boardlistCopy[0].data[1].list.push({id: 2, task: "studying React"});
setBoardlist(boardlistCopy);

Related

Comparing two arrays of objects if one property is also an array in Angular 7?

I have two arrays:
First - jobs array of objects that contains array itemIds, like this:
jobs: [{
name: null
id: 612
items: []
stat: 1
itemIds: [223, 1234]
},
{
name: null
id: 734
items: []
stat: 2
itemIds: [564]
}
.
.
.
]
and second array - items, like this:
items: [{
act: true
id: 1234
name: "Item1"
},
{
act: true
id: 222
name: "Item2"
},
]
How to filter out an array of items whos id isn't equal to any of itemIds from jobs array or that property stat from jobs array isn't equal to 0 ?
I tried with three loops, but it dropped out only one item with the same id in a array of jobs.
Any help appreciated.
We are going to use Array.filter to loop over every elements in items and create a new array containing only the items you want to keep.
For each of the values, we are going to see if any job contains in itemIds the code id. To do that, we are going to loop over every job and for every job, we are going to look at the underlying ItemsIds values.
Array.some here will leave as soon at it find something.
const jobs = [{
name: null,
id: 612,
items: [],
stat: 1,
itemIds: [223, 1234],
},
{
name: null,
id: 612,
items: [],
stat: 2,
itemIds: [223, 1234],
},
{
name: null,
id: 734,
items: [],
stat: 2,
itemIds: [564],
}
];
const items = [{
act: true,
id: 1234,
name: 'Item1',
},
{
act: true,
id: 222,
name: 'Item2',
},
];
const filteredItems = items.filter(x => jobs.some(y => y.itemIds.includes(x.id) && y.stat !== 1));
console.log(filteredItems);

How to combine a flat arrays into hierarchy in Javascript

say I have a data structure like this:
const flat = [
[
{
id: 0,
schema: "class",
name: "basement below baseLevel"
}
{
id: 1,
schema: "class",
name: "baseLevel"
},
{
id: 2,
schema: "TopLevelClass",
name: "The Top"
},
],
[
{
id: 3,
schema: "class",
name: "Second base level"
},
{
id: 2,
schema: "TopLevelClass",
name: "The Top"
}
]
]
The structure assumes a nested hierarchy where the root is the last element of each inner array. I need to restructure the data to look like this:
const root = [
id: 2,
schema: "TopLevelClass",
name: "The Top",
children: [
{
id: 1,
schema: "class",
name: "base Level",
children: [
{
id: 0,
schema: "class",
name: "Basement below base level"
}
]
},
{
id: 3,
schema: "class",
name: "Second base level"
}
]
]
There are some examples that combine arrays into hierarchies similar to this, but they always include either a parent or child id and the data structure I am working with does not. It just assumes (I know this is probably not a good assumption to be making, but its what I am working with) that each inner array is structured base up. Is there a concise way to nest the flattened array into a hierarchy?
Thanks!

map deep in collection

I need to get all "id" and "name" of a big collection I have. An array ob objects, that has array with objects (etc).
I can't get it to work without manually doing foreaches for as many levels there is, which is ugly.
I am using Lodash, so a solution using this would be lovely.
This is how the collection looks like:
[
{
"id": 1,
"name": "Living",
"numberStories": 0,
"subcategories": {
"data": [
{
"id": 2,
"name": "Fashion",
"numberStories": 0,
"subcategories": {
"data": [
{
"id": 3,
"name": "Accessories",
"numberStories": 0,
"subcategories": {
"data": [
]
}
},
{
"id": 4,
"name": "Kid's Fashion",
"numberStories": 0,
"subcategories": {
"data": [
]
}
}, (... etc)
So it needs to look in subcategories in each array of objects and collect id and name, so that I end up with all the ids names from all levels.
Thanks.
As above, this is probably easier to do with native javascript as it's recursive. This is the same idea as the previous answer, but using some cool features of ES6 (destructuring, rest params, arrow functions, default parameters), and it will save a reference to the parent id so you can rebuild the category tree if you need.
const categories=[{id:1,name:"Living",numberStories:0,subcategories:{data:[{id:2,name:"Fashion",numberStories:0,subcategories:{data:[{id:3,name:"Accessories",numberStories:0,subcategories:{data:[]}},{id:4,name:"Kid's Fashion",numberStories:0,subcategories:{data:[]}}]}}]}}];
const flattenCategories = (categories, parent = null, ret = []) =>
categories.reduce((acc, { id, name, subcategories: { data } }) =>
acc.concat(
{ id, name, parent },
...flattenCategories(data, id)
)
, ret)
console.log(
flattenCategories(categories)
)
.as-console-wrapper { top: 0; max-height: 100% !important }
There's no need to use lodash for this purpose. A simple recursive function using .reduce() does the job for you
function flattenId(inArray){
return inArray.reduce(function(output, elem){
output.push(elem.id);
return output.concat(flattenId(elem.subcategories.data));
}, []);
}
Here is a solution using object-scan. Depending on your use case it might be overkill to use a library, but if so desired it can give you a lot more flexibility
// const objectScan = require('object-scan');
const categories = [{ id: 1, name: 'Living', numberStories: 0, subcategories: { data: [{ id: 2, name: 'Fashion', numberStories: 0, subcategories: { data: [{ id: 3, name: 'Accessories', numberStories: 0, subcategories: { data: [] } }, { id: 4, name: "Kid's Fashion", numberStories: 0, subcategories: { data: [] } }] } }] } }];
const r = objectScan(['**[*].id'], {
filterFn: ({ context, value, parents }) => {
context.push({
id: value,
name: parents[0].name,
parent: parents.length > 2 ? parents[3].id : null
});
}
})(categories, []);
console.log(r);
// => [ { id: 4, name: "Kid's Fashion", parent: 2 }, { id: 3, name: 'Accessories', parent: 2 }, { id: 2, name: 'Fashion', parent: 1 }, { id: 1, name: 'Living', parent: null } ]
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/object-scan#13.8.0"></script>
Disclaimer: I'm the author of object-scan

Setting deep associations in normalizr schema

I have a server response that looks like this:
[{
id: 1,
title: 'Some Article',
related_articles: {
total: 4,
results: [
{ id: 2, title: 'Some other article' },
{ id: 3, title: 'Yet another article' },
]
}
}]
As you can see, what makes this tricky is it isn't a simple arrayOf: I want to normalize article.related_articles.results.
I've tried this, to no avail:
articleSchema.define({
related_articles: {
results: arrayOf(relatedArticleSchema),
},
});
It seems as though supported relations have to be "top level".
Anyone know how I can wind up with something like:
[{
id: 1,
title: 'Some Article',
related_articles: {
total: 4,
results: [2, 3]
}
}]
Thanks!
Your scheme defines a key "relatedArticles", but it should be snake_case, "related_articles"

How to use normalizr to flatten an array with different types of objects?

So, I get a JSON response from the server that looks something like:
{
data: [
{ id: 1, type: 'person', emails: [ { id: 1 }, { id: 3 } ], phones: [] },
{ id: 2, type: 'person', emails: [ { id: 2 } ], phones: [ { id: 2 } ] },
{ id: 3, type: 'person', emails: [ { id: 4 } ], phones: [ { id: 3 }, { id: 3 }] }
],
included: [
{ id: 1, type: 'emails', ... },
{ id: 2, type: 'emails', ... },
{ id: 3, type: 'emails', ... },
{ id: 4, type: 'emails', ... },
{ id: 1, type: 'phones', ... },
{ id: 2, type: 'phones', ... },
{ id: 3, type: 'phones', ... }
]
}
The data property is an array of contact objeccts all with the same structure. Each contact object has an array of related emails and phones.
The included property is an array of ALL types of related objects which means they can share and id or even have a difference object structure.
I'm looking to try and flatten the response to be easier to work with and resemble:
{
entities: {
contacts: [ ... ],
emails: [ ... ],
phones: [ ... ]
},
result: [ 1, 2, 3 ]
}
I've managed to normalize just the contact data using:
const contactSchema = new schema.Entity('contacts');
const contactListSchema = [ contactSchema ];
const normalizedData= normalize(response, contactListSchema);
But that obviously won't include the emails or phones in the entities.
I don't actually know if this library is capable of what I'm trying to achieve, but any help would be appreciated.
While not based on the data above, the API is based off of the jsonapi.org schema, so the example on the homepage matches exactly with the structure.
I actually found a library specifically designed to do this based on the original normalizr:
https://github.com/stevenpetryk/jsonapi-normalizer
Hope this may help someone in the future!

Categories