I have an array objects
it looks like
\[
{id: 1, name: 'first', properties: \[{id: 1, name: 'propName1'}, {id: 2, name: 'propName2'}\]},
{id: 2, name: 'second', properties: \[{id: 1, name: 'propName1'}, {id: 2, name: 'propName2'}\]},
{id: 3, name: 'third', properties: \[{id: 1, name: 'propName1'}, {id: 2, name: 'propName2'}\]},
\]
I want to display first name of object for example 'first' and then I want to display names of properties objects propName1, propName2
so I want to see
first
propName1
propName2
second
propName1
propName2
third
propName1
propName2
Could you help me, guys?
I tried
{filters.map((filter) => {
let propss = ArrayFrom(filter.properties);
propss.map((prop) => (
<div>{prop.displayName}</div>
))
return(
<div className={style.title}>{filter.displayName}</div>
)
filter.properties.map((prop) => {
return (
<>
<div className={style.title}>{filter.displayName}</div>
<div>{prop.displayName}</div>
</>
);
});
})}
and I tried to save array via reduce, but without any result
First of all, you should not name yout array 'filter' since this can be confused with the Array.prototype.filter method ;)
Then you have an array of objects containing arrays, so you should iterate at the two level (in case your real structure actually gots more depth, you probably need to take a recursive approach).
considering your entry point :
const data = [
{
id: 1,
name: 'first',
properties: [
{id: 1, name: 'propName1'},
{id: 2, name: 'propName2'}
]
}, {
id: 2,
name: 'second',
properties: [
{id: 1, name: 'propName1'},
{id: 2, name: 'propName2'}
]
}, {
id: 3,
name: 'third',
properties: [
{id: 1, name: 'propName1'},
{id: 2, name: 'propName2'}
]
},
]
the two iterations couls look like somthing like that :
return data.map(entry => (
<>
<div className={style.title}>{entry.name}</div>
{entry.properties.map(prop => (
<div>{prop.name}</div>
))}
<>
))
Related
I'm using treeview to display my hierarchical data.
I have following array of objects:
const data = [
{ id: 1, hierarchyid: "/", level: 0, name: "Mhz" },
{ id: 2, hierarchyid: "/2/", level: 1, name: "SMT" },
{ id: 3, hierarchyid: "/3/", level: 1, name: "QC" },
{ id: 4, hierarchyid: "/3/4/", level: 2, name: "Tester" },
{ id: 5, hierarchyid: "/3/5/", level: 2, name: "Operator" },
];
I need to fill my treeview with this data.
What I did so far:
getTreeItems(node, nodes) {
const filtered = nodes.filter(
(n) => n.hierarchyid.includes(node.hierarchyid) && n.level != node.level
);
return (
<TreeItem
key={node.id}
nodeId={node.hierarchyid}
label={node.name}
onClick={() => onClicked(node)}
>
{filtered.length > 0
? filtered.map((node) => this.getTreeItems(node, filtered))
: null}
</TreeItem>
);
}
And rendering:
render() {
// The data comes from Server
const data = [
{ id: 1, hierarchyid: "/", level: 0, name: "Mhz" },
{ id: 2, hierarchyid: "/2/", level: 1, name: "SMT" },
{ id: 3, hierarchyid: "/3/", level: 1, name: "QC" },
{ id: 4, hierarchyid: "/3/4/", level: 2, name: "Tester" },
{ id: 5, hierarchyid: "/3/5/", level: 2, name: "Operator" },
];
return (
<TreeView
aria-label="file system navigator"
defaultCollapseIcon={<ExpandMoreIcon />}
defaultExpandIcon={<ChevronRightIcon />}
sx={{ height: "auto", flexGrow: 1, width: "auto", overflowY: "auto" }}
>
{this.getTreeItems(
{ id: 1, hierarchyid: "/", level: 0, name: "Mhz" },
data
)}
</TreeView>
);
}
}
This giving me view like:
+Mhz
+SMT
+QC
+Tester
+Operator
+Tester // they shouldn't be displayed
+Operator // they have already rendered as child under QC
My problem is can not exclude already rendered nodes.
Update
MUI TreeView supports special JSON data for its nodes. So converting array to JSON also solves the problem. Something like that:
const data = {
id: 1,
hierarchyid: "/",
level: 0,
name: "Mhz",
children: [
{
id: 2,
hierarchyid: "/2/",
level: 1,
name: "SMT"
},
{
id: 3,
hierarchyid: "/3/",
level: 1,
name: "QC",
children: [
{
id: 4,
hierarchyid: "/3/4/",
level: 2,
name: "Tester"
},
{
id: 5,
hierarchyid: "/3/5/",
level: 2,
name: "Operator"
}
]
}
]
};
the array of objects came from Server, so how can I make this Json from array data?
If we write a quick function to test whether one hierarchy id is the direct descendant of another, then we can use it to write a simple recursive version:
const isChild = (prefix) => ({hierarchyid}) =>
hierarchyid .startsWith (prefix)
&& /^[^\/]*\/$/ .test (hierarchyid .slice (prefix .length))
const nest = (xs, prefix = '') =>
xs .filter (isChild (prefix)) .map ((x, _, __, children = nest (xs, x .hierarchyid)) => ({
...x,
... (children .length ? {children} : {})
}))
const data = [{id: 1, hierarchyid: "/", level: 0, name: "Mhz"}, {id: 2, hierarchyid: "/2/", level: 1, name: "SMT"}, {id: 3, hierarchyid: "/3/", level: 1, name: "QC"}, {id: 4, hierarchyid: "/3/4/", level: 2, name: "Tester"}, {id: 5, hierarchyid: "/3/5/", level: 2, name: "Operator"}]
console .log (nest (data))
.as-console-wrapper {max-height: 100% !important; top: 0}
isChild checks whether the hierarchy id starts with our prefix and if the remainder has only one '/', at the very end.
nest is not as efficient as it might be, as it scans the whole array for each node. But I wouldn't worry about it until I had tens of thousands of entries.
If you don't mind having some empty children arrays on your leaves, it's simpler still:
const nest = (xs, prefix = '') =>
xs .filter (isChild (prefix)) .map ((x) => ({
...x,
children: nest (xs, x .hierarchyid)
}))
SO I've looked at the documentation and they've clearly mentioned a way to design your data object in such a way so that the hierarchy can be shown without multiple nodes repeating.
Try going through this once and change your render functions according to the documentation, you can probably get your desired result.
const data: RenderTree = {
id: "root",
name: "Mhz",
children: [
{
id: "1",
name: "SMT"
},
{
id: "3",
name: "QZ",
children: [
{
id: "4",
name: "Tester"
},
{
id: "4",
name: "Operator"
}
]
}
]
};
I have a following array
const _array = [{id: 1, name: 'Adam'}, {id:3, name: 'Crystal'}, {id:2, name: 'Bob'}, {id: 4, name: 'Daisy'}];
How to write a single line of code in typescript to get item where name equal to Crystal from the array?
You can use array find method like following:
const _array = [
{ id: 1, name: "Adam" },
{ id: 3, name: "Crystal" },
{ id: 2, name: "Bob" },
{ id: 4, name: "Daisy" },
];
const item = _array.find((item) => item.name === "Crystal");
console.log(item);
Output
{ id: 3, name: 'Crystal' }
I have an array of projects called rawProjects which looks like this:
rawProjects = [
{
id: 1,
name: "proj1",
technology: [
0: {id: 21, project_id: 1,name: "java"},
1: {id: 22, project_id: 1,name: "c++"}
]
},
{
id: 2,
name: "proj2",
technology: [
0: {id: 23, project_id: 2,name: "sql"},
1: {id: 24, project_id: 2,name: "python"},
2: {id: 25, project_id: 2,name: "react"}
]
}
]
I also have an array of technology called tempTags which contains the technologies that the user enters to search from. So far I have been able to do the OR case where in I return the projects which contain either of the technologies mentioned by the user using:
const filteredProjects = rawProjects.filter(x => x.technology.some(g => tempArr.includes(g.name)))
So for example if tempTags = [sql, c++] both projects will be returned.
How do I implement the AND case such that only projects that contain both of these technologies are returned. Eg if tempTags = [java, c++] , only the first project will be returned. If tempTags = [sql, c++], nothing will be returned?
Iterate over the tempTags and check that .every one of them is included:
const rawProjects = [
{
id: 1,
name: "proj1",
technology: [
{id: 21, project_id: 1,name: "java"},
{id: 22, project_id: 1,name: "c++"}
]
},
{
id: 2,
name: "proj2",
technology: [
{id: 23, project_id: 2,name: "sql"},
{id: 24, project_id: 2,name: "python"},
{id: 25, project_id: 2,name: "react"}
]
}
]
const tempTags = ['java', 'c++'];
const filtered = rawProjects.filter(
p => {
const techNames = p.technology.map(({ name }) => name);
return tempTags.every(
tag => techNames.includes(tag)
);
}
);
console.log(filtered);
You'll also need to fix your syntax: arrays do not have key-value pairs, only values. (Remove the 0:, 1:, etc), and make sure to put commas in between array values (there should be a comma after "python"})
Given the following data set:
const accounts = [
{id: 2, children: [1,22,69], parentId: null},
{id: 3, children: [140, 122, 580], parentId: null},
{id: 1, children: [4,5,6], parentId: 2},
{id: 22, children: [8,9,2], parentId: 2},
{id: 4, children: [45,54,61], parentId: 1},
{id: 6, children: [40,89,20], parentId: 1},
{id: 40, children: [], parentId: 6},
....
]
I need to create a function that takes and id as argument and returns a tree, starting with the top most level parent and it's children (and siblings).
In the above example, there are only 2 top level "accounts", id:2 and id:3. So the function call might look like findTree(89) , it should return the tree starting with the account id 2, and it's children, but will obviously leave out account id 3 and it's children, since that top level account has nothing to do with top level account of id 2, so the ideal response would be:
{
id: 2,
children: [
{ id: 1, children: [{id: 540, children: [{ id: 78},{}], parentId:1], parentId: 2},
.....
],
parentId: null
}
What would be the best way to go about it ? I've tried a recursive function but I'm not getting anywhere near to a solution.
EDIT: Here part of the code:
(groupArray is an array containing all items in a flat list, without hierarchy)
const makeTreeById = itemId => {
const startNode = _.find(groupArray, {id: itemId}) // grab the actual item, not the id
findTopParent(startNode)
}
and then the findTopParent fn
const findTop = item => {
let top = item;
if(top.parentId) {
top = _.find(groupArray, {id: top.parentId}
return findTop(top)
}
return top;
}
I was creating that function to simply have it return the top level account and from there I was planning on constructing the actual tree, the problem is that top does get me the top level but at some point it get reassigned with the immediate parent.
SECOND EDIT: Sorry about all the confusion guys, as you can see, I'm really new.
I have an array that includes all items I would need. So it kinda looks like this:
// children here are only ids, not the actual elements, the element are part of // the list, but the children array for each element is just a reference.
data = [
{id: 1, children: [4,5,6], parentId: null},
{id: 2, children: [7,8,9], parentId: null},
{id: 3, children: [10,11,12], parentId: null},
{id: 4, children: [13,14,15], parentId: 1},
{id: 10, children: [20,21,22], parentId: 3}
{id: 14, children: [], parentId: 4}
....
]
You can find the desired results with function topParent. Just look for parent being null in each iteration.
const accounts = [
{id: 2, children: [1,22,69], parentId: null},
{id: 3, children: [140, 122, 580], parentId: null},
{id: 1, children: [4,5,6], parentId: 2},
{id: 22, children: [8,9,2], parentId: 2},
{id: 4, children: [45,54,61], parentId: 1},
{id: 6, children: [40,89,20], parentId: 1},
{id: 40, children: [], parentId: 6}
];
function topParent(id) {
var obj = accounts.find((v) => v.id == id);
return obj.parentId == null ? obj : topParent(obj.parentId)
}
console.log(topParent(6));
actually they are many way to achieve the expected tree. In performance manner you should determine if you will have complexity (in term of iteration) on the deep of your tree or | and on how many items in total you will have.
I have assume the complexity will be more on how many items in total you will have.
exemple : big amount of accounts with only small amount of nested childrens.
Introduction : Following you have type and sample array.
interface IEntity {
id: number;
children: number[];
parentId?: number;
}
interface IEntityNested {
id: number;
children: IEntityNested[];
parentId?: number;
}
const accounts: IEntity[] = [
{id: 1, children: [3], parentId: null},
{id: 2, children: [], parentId: null},
{id: 3, children: [4], parentId: 1},
{id: 4, children: [], parentId: 3},
];
For that i prupose you to start by searching for any particular id what is the top of you tree. The element which doesn't have any other top element.
const findTopParent = (id: number): IEntity => {
let account = accounts.find(acc => acc.id === id);
if(account.parentId !== null) {
account = findTopParent(account.parentId);
}
return account;
};
For id 4 it should return account id 1
const topParent = findTopParent(4);
console.log(topParent.id); // Print 1.
then from your topParent you can build the nested tree from the top to the bottom.
const buildTreeFromSpecificAccount = (account: IEntity): IEntityNested => {
const nestedAccount = {...account,children: []};
account.children.forEach(childId => {
nestedAccount.children.push(
buildTreeFromSpecificAccount(
accounts.find(acc => acc.id === childId)
)
);
})
return nestedAccount;
}
// Build the tree from the top parent.
const tree = buildTreeFromSpecificAccount(topParent);
And voilĂ !
Side note :
You can way more improve the performance by changing your data array by indexed object like following :
const accountOrdered: {[id: number]: IEntity} = {
1: {id: 1, children: [3], parentId: null},
2: {id: 2, children: [], parentId: null},
3: {id: 3, children: [4], parentId: 1},
4: {id: 4, children: [], parentId: 3},
};
Like this instead of doing accounts.find(acc => acc.id === childId) looping on your array to find entry by id. you can do accountOrdered[childId]
live sample
I have a hard reading the ImmutableJS and other questions answers... It seems simple, I have a Map like this :
{
foo: [
{id: 1, name: 'John'},
{id: 2, name: 'Christine'},
{id: 3, name: 'Frank'},
{id: 4, name: 'Jenny'},
]
}
How can i update change "John" to "Johnny" ?
From the docs you can use this:
newMap = oldMap.setIn(['foo', 0, 'name'], 'Johnny');
You pass an array of keys, then the value.