i need to loop array from backend in js file to show some chart data. I need variable called events that contains array of data from backend. but from backend it comes as array too, so how i can loop it, so here's code, for better understanding
var events = [
{
id: 1,
url: "",
title: "TEST 1",
start: "2023-02-12",
extendedProps: {calendar: "Personal"}
}, {
id: 1,
url: "",
title: "TEST 1",
start: "2023-02-12",
extendedProps: {calendar: "ETC"}
}, {
id: 2,
url: "",
title: "Meeting With Client",
start: "2023-02-12",
extendedProps: {calendar: "Holiday"}
}
];
I have more than 100 those kinds of data, so i need to loop them inside of array
I'm not sure if that's what you mean, but if you simply need to loop through your variable "events":
events.forEach(el => {
console.log(el)
})
and if you need to loop through each object attribute:
events.forEach(el => {
for(let i in el) {
console.log(el[i])
}
})
Is this what you needed?
Related
I have an array nested with an array of objects, the problem is that I don't understand how to filter the entire property by title at once.
At the moment, filtering for the title property works fine for me, but it only works for the top level, that is, it does not work inside the elems array.
At the moment, my code looks like this
state: {
searchValue: "",
categories: [
{
title: "about",
open: false,
elems: [{ title: "portfolio" }],
},
{
title: "services",
open: false,
elems: [{ title: "jobs" }],
},
],
},
getters: {
categories(state) {
return state.categories.filter(item => {
return item.title.toLowerCase().includes(state.searchValue.toLowerCase())
})
}
}
And in the end, for a better understanding, I would like to tell what I want to achieve when the user enters the word about or portfolio into the input, for example, I want to show the first object if the word jobs or services is entered, I want to show the second object, but again, the title property of the first level works for me, but the title property inside the elems array does not work.
You can try with some for nested array:
let searchValue = "about"
const categories = [
{title: "about", open: false, elems: [{ title: "portfolio" }],},
{title: "services", open: false, elems: [{ title: "jobs" }, { title: "about" }],},
]
function cats(state) {
return state.filter(item => {
return item.title.toLowerCase().includes(searchValue.toLowerCase()) ||
item.elems.some(e => e.title.toLowerCase().includes(searchValue.toLowerCase()))
})
}
console.log(cats(categories))
I have a json tree structure that I want to normalize into something like a hashmap and then denormalize it back to a tree if needed.
I have a very dynamic tree that I want to use as state in my react-redux project, but for that I somehow need to transform the data so that I can access it without having to search elements recursively in the tree each time I want to update/access the state.
const actual = {
id: "1",
type: 'Container',
data: {},
items: [
{
id: "2",
type: "Subcontainer",
data: {
title: "A custom title",
text: "A random Headline"
},
items: []
},
{
id: "3",
type: "Subcontainer",
data: {
title: "A custom title",
text: "A random Headline"
},
items: []
}
]
};
Now I want to transform it into something like:
const expected = {
1: {
id: "1",
type: 'Container',
data: {},
items: [1, 2]
},
2: {
id: "2",
type: "Subcontainer",
data: {
title: "A custom title",
text: "A random Headline"
},
items: []
},
3: {
id: "3",
type: "Subcontainer",
data: {
title: "A custom title",
text: "A random Headline"
},
items: []
}
};
I found a JS lib called Normalizr, but I absolutely don't get how to create the schemas for it to work.
That was my last try, and it returns only the inner two items and also directly the data object inside without id, items around:
const data = new schema.Entity("data");
const item = new schema.Object({ data });
item.define({ items: new schema.Array(item) });
const items = new schema.Array(item);
const normalizedData = normalize(mock, items);
I'm not going to worry too much about the types, since you can alter those to meet your needs. Going off you're example, I will define
interface Tree {
id: string;
type: string;
data: {
title?: string;
text?: string;
items: Tree[];
}
}
interface NormalizedTree {
[k: string]: {
id: string;
type: string;
data: {
title?: string;
text?: string;
items: string[]
}
}
}
and we want to implement function normalize(tree: Tree): NormalizedTree and function denormalize(norm: NormalizedTree): Tree.
The normalize() function is fairly straightforward since you can recursively walk the tree and collect the normalized trees into one big normalized tree:
function normalize(tree: Tree): NormalizedTree {
return Object.assign({
[tree.id]: {
...tree,
data: {
...tree.data,
items: tree.data.items.map(v => v.id)
}
},
}, ...tree.data.items.map(normalize));
}
In English, we are making a single normalized tree with a property with key tree.id and a value that's the same as tree except the data.items property is mapped to just the ids. And then we are mapping each element of data.items with normalize to get a list of normalized trees that we spread into that normalized tree via the Object.assign() method. Let's make sure it works:
const normalizedMock = normalize(mock);
console.log(normalizedMock);
/* {
"1": {
"id": "1",
"type": "Container",
"data": {
"items": [
"2",
"3"
]
}
},
"2": {
"id": "2",
"type": "Subcontainer",
"data": {
"title": "A custom title",
"text": "A random Headline",
"items": []
}
},
"3": {
"id": "3",
"type": "Subcontainer",
"data": {
"title": "A custom title",
"text": "A random Headline",
"items": []
}
}
} */
Looks good.
The denormalize() function is a little trickier, because we need to trust that the normalized tree is valid and actually represents a tree with a single root and no cycles. And we need to find and return that root. Here's one approach:
function denormalize(norm: NormalizedTree): Tree {
// make Trees with no children
const treeHash: Record<string, Tree> =
Object.fromEntries(Object.entries(norm).
map(([k, v]) => [k, { ...v, data: { ...v.data, items: [] } }])
);
// keep track of trees with no parents
const parentlessTrees =
Object.fromEntries(Object.entries(norm).map(([k, v]) => [k, true]));
Object.values(norm).forEach(v => {
// hook up children
treeHash[v.id].data.items = v.data.items.map(k => treeHash[k]);
// trees that are children do have parents, remove from parentlessTrees
v.data.items.forEach(k => delete parentlessTrees[k]);
})
const parentlessTreeIds = Object.keys(parentlessTrees);
if (parentlessTreeIds.length !== 1)
throw new Error("uh oh, there are " +
parentlessTreeIds.length +
" parentless trees, but there should be exactly 1");
return treeHash[parentlessTreeIds[0]];
}
In English... first we copy the normalized tree into a new treeHash object where all the data.items are empty. This will eventually hold our denormalized trees, but right now there are no children.
Then, in order to help us find the root, we make a set of all the ids of the trees, from which we will remove any ids corresponding to trees with parents. When we're all done, there should hopefully be a single id left, that of the root.
Then we start populating the children of treeHash's properties, by mapping the corresponding data.items array from the normalized tree to an array of properties of treeHash. And we remove all of these child ids from parentlessTreeIds.
Finally, we should have exactly one property in parentlessTreeIds. If not, we have some kind of forest, or cycle, and we throw an error. But assuming we do have a single parentless tree, we return it.
Let's test it out:
const reconsitutedMock = denormalize(normalizedMock);
console.log(reconsitutedMock);
/* {
"id": "1",
"type": "Container",
"data": {
"items": [
{
"id": "2",
"type": "Subcontainer",
"data": {
"title": "A custom title",
"text": "A random Headline",
"items": []
}
},
{
"id": "3",
"type": "Subcontainer",
"data": {
"title": "A custom title",
"text": "A random Headline",
"items": []
}
}
]
}
} */
Also looks good.
Playground link to code
I would recommend .flatMap for this kind of transformations:
const flattenTree = element => [
element,
...element.data.items.flatMap(normalizeTree)
]
This move you from this shape:
{
id: 1,
data: { items: [
{
id: 2,
data: { items: [
{ id: 3, data: { items: [] } },
] }
] }
}
to this one:
[
{ id: 1, data: {...}},
{ id: 2, data: {...}},
{ id: 3, data: {...}},
]
Then once you have a flat array, you can transform it further to remove the references and create an object from entries:
const normalizedTree = element => {
let flat = flattenTree(element)
// only keep the id of each items:
// [{ id: 1, data:{...}}] -> [1]
// for (const el of flat) {
// el.data.items = el.data.items.map(child => child.id)
// }
// note that the for loop will change the initial data
// to preserve it you can achieve the same result with
// a map that will copy every elements:
const noRefs = flat.map(el => ({
...el,
data: {
...el.data,
items: el.data.items.map(child => child.id),
},
}))
// then if you need an object, 2 steps, get entries, [id, elem]:
const entries = noRefs.map(({ id, ...element }) => [id, element])
// then the built-in `Object.fromEntries` do all the work for you
// using the first part of the entry as key and last as value:
return Object.fromEntries(entries)
// if you have multiple objects with the same id's, only the last one
// will be in your returned object
}
I am trying to update a nested value of an object using the spread operator. This is my first time using this and I believe I am pretty close to achieving my end goal but I just can't seem to figure out what I actually need to do next.
I have an array which is structured like this:
[
{
name: "Category 1",
posts: [
{
id: 1,
published: false,
category: "Category 1"
},
{
id: 2,
published: true,
category: "Category 1"
}
]
},
{
name: "Category 2",
posts: [
{
id: 3,
published: true,
category: "Category 2"
},
{
id: 4,
published: true,
category: "Category 2"
}
]
}
]
On the click of a button I am trying to update the published value, and as I am using React I need to set the state. So it got recommended to me that I update using the spread operator.
onPostClick(post) {
post.pubished = !post.published;
this.setState({...this.state.posts[post.category], post})
}
If I log out the result of {...this.state.posts[post.category], post} I can see that the published is getting added to the parent which forms:
{
name: "Category 1",
published: false,
posts: [
...
]
}
Obviously this isn't the intended result, I want it to update the actual object within the posts object.
I have tried to do something like this.setState({...this.state.posts[post.category].posts, post}) but I get a message that it is undefined.
You can't access your data with this.state.posts[post.category]. posts data in the objects of the array.
You can make a filter to find your category object in array and change its posts value.
onPostClick(post) {
//CLONE YOUR DATA
var postArray = this.state.posts;
//FIND YOUR CATEGORY OBJECT IN ARRAY
var categoryIndex = postArray.findIndex(function(obj){
return obj.name === post.category;
});
//FIND YOUR POST AND CHANGE PUBLISHED VALUE
postArray[categoryIndex].posts.forEach(function(item){
if (item.id === post.id) {
item.published = !item.published;
}
});
//SET TO STATE TO RERENDER
this.setState({ posts: postArray});
}
This should work if your name of the state is true.
just adding, we know there are many ways to succeed, maybe you also want to try this way too..
onPostClick = post => {
let published = this.state.data.map((item, i) => {
item.posts.map((item_post, i) => {
if (item_post.category === post.category) {
item_post.published = !post.published;
}
});
});
this.setState({ ...this.state.data, published });
};
I have my data as following:
{
meta: {
format: "csv",
info: "desc",
columns: [
{
id: "Name",
type: "Text",
length: 32
},
{
id: "Text",
type: "Text",
length: 128
}]
},
rows: [
["John","xxxx"],
["Alpha","yyyy"],
["Beta","wwww"],
["Gamma","zzzz"]]
}
Now, I am struggling to map the records to a Table control as Columns and Rows. Column seems straight forward, straight map, but the rows since lacks a mapping to column I wonder what could be the simplest way.
Approach Steps:
Make a keys[] from column.id of each columns record.
Traverse the rows[]
Each loop, while keys.length create an object as {keys[j]:row[k]}
Push to an array
Recreate the original JSON but replace Rows arrays with Objects
I am really struggling to translate this into code specially at the rows[] parsing and creating Objects. Is there, I am sure there must be, an efficient way to achieve this.
Here is what you could do. using Array.map and forEach.
var input = {
meta: {
format: "csv",
info: "desc",
columns: [{
id: "Name",
type: "Text",
length: 32
}, {
id: "Text",
type: "Text",
length: 128
}]
},
rows: [
["John", "xxxx"],
["Alpha", "yyyy"],
["Beta", "wwww"],
["Gamma", "zzzz"]
]
};
var columns = input.meta.columns.map((column) => {
return column.id
});
var rows = input.rows.map((row) => {
var obj = {};
row.forEach((column, idx) => {
obj[columns[idx]] = column;
});
return obj;
});
input.rows = rows;
console.log(input);
I have following data Structure which I want to use in data structure given in Dyntree Format:
[
{
title: "my Title",
isFolder: "true",
key: 1
}
]
I am setting above data structure as STRING in a JS variable.
When I set this value as a javascript variable, it gives error of Invalid Type
DynTree format is given below;
var fakeJsonResult = [
{ title: 'Lazy node 1', isLazy: true },
{ title: 'Simple node 2', select: true }
];
This is simple if you want to create a dynatree from the object you mentioned simply do this
var children = [
{
title: "my Title",
isFolder: "true",
key: 1
}
];
$('#tree').dynatree({
children : children
});