I working on a react project using Antd and I want to be able to disable cheking childs of my Tree component, so I can check only parent.This is my code
I found that I can add checkable : false to my child but I must create a function that render me a new TreeData that I can use instead of my normal data so I've tried this :
const TreeData = (data) => {
data.map((category) => {
category.children.map((family) => {
family.children.map((table) => {
table.checkable = false;
});
});
});
};
But it return undefined when i'm console.log the data received..
So my question is : how to switch from this :
const treeData = [
{
title: "0-0",
key: "0-0",
children: [
{
title: "0-0-0",
key: "0-0-0",
children: [
{
title: "0-0-0-0",
key: "0-0-0-0"
},
{
title: "0-0-0-1",
key: "0-0-0-1"
},
{
title: "0-0-0-2",
key: "0-0-0-2"
}
]
},
{
title: "0-0-1",
key: "0-0-1",
children: [
{
title: "0-0-1-0",
key: "0-0-1-0"
},
{
title: "0-0-1-1",
key: "0-0-1-1"
},
{
title: "0-0-1-2",
key: "0-0-1-2"
}
]
},
{
title: "0-0-2",
key: "0-0-2"
}
]
},
{
title: "0-1",
key: "0-1",
children: [
{
title: "0-1-0-0",
key: "0-1-0-0"
},
{
title: "0-1-0-1",
key: "0-1-0-1"
},
{
title: "0-1-0-2",
key: "0-1-0-2"
}
]
},
{
title: "0-2",
key: "0-2"
}
];
To this :
const treeData = [
{
title: "0-0",
key: "0-0",
children: [
{
checkable: false,
title: "0-0-0",
key: "0-0-0",
children: [
{
title: "0-0-0-0",
key: "0-0-0-0"
},
{
title: "0-0-0-1",
key: "0-0-0-1"
},
{
title: "0-0-0-2",
key: "0-0-0-2"
}
]
},
{
checkable: false,
title: "0-0-1",
key: "0-0-1",
children: [
{
title: "0-0-1-0",
key: "0-0-1-0"
},
{
title: "0-0-1-1",
key: "0-0-1-1"
},
{
title: "0-0-1-2",
key: "0-0-1-2"
}
]
},
{
checkable: false,
title: "0-0-2",
key: "0-0-2"
}
]
},
{
title: "0-1",
key: "0-1",
children: [
{
checkable: false,
title: "0-1-0-0",
key: "0-1-0-0"
},
{
checkable: false,
title: "0-1-0-1",
key: "0-1-0-1"
},
{
checkable: false,
title: "0-1-0-2",
key: "0-1-0-2"
}
]
},
{
title: "0-2",
key: "0-2"
}
];
Without hardchanging the first data of my Tree.
Thank you
This may be one possible implementation to set checkable as false for the specific nodes described in this question:
const makeUnCheckable = dataArr => (
dataArr.map(
obj => ({
...obj,
children: obj?.children?.map(cObj => ({
...cObj,
checkable: false
}))
})
)
);
return (
<Tree
checkable
onExpand={onExpand}
expandedKeys={expandedKeys}
autoExpandParent={autoExpandParent}
onCheck={onCheck}
checkedKeys={checkedKeys}
onSelect={onSelect}
selectedKeys={selectedKeys}
treeData={makeUnCheckable(treeData)}
/>
);
This is the result displayed on Codesandbox:
NOTES:
The elements showing as checked are clicked manually.
There is no check option for nodes 0-0-0, 0-0-1, 0-0-2, 0-1-0-0, 0-1-0-1, 0-1-0-2 - which is the expected objective defined in the question under To this
EDITED:
On perusing this previous question it seems like OP requires something like this:
(A tree where leaf nodes are uncheckable)
This may be achieved by a recursive method - something like this:
(Changes are present in: Lines 100 to 106. And line 118.)
EDITED - 2
Update based on comments below.
In order to identify the children for any given parent/key, something like the below may be useful:
Two methods are here. One is findKey which is recursive and gets the object which has a particular key (say 0-0-1). The other is to check if the object with the key has any children and if yes, return the children array.
Related
This question already has answers here:
Tree structure to flat array Javascript
(2 answers)
Closed 12 months ago.
I want to get length of multidimentionnal array in JS :
This is my array :
const treeData = [
{
title: '0-0',
key: '0-0',
children: [
{
title: '0-0-0',
key: '0-0-0',
children: [
{
title: '0-0-0-0',
key: '0-0-0-0',
},
{
title: '0-0-0-1',
key: '0-0-0-1',
},
{
title: '0-0-0-2',
key: '0-0-0-2',
},
],
},
{
title: '0-0-1',
key: '0-0-1',
children: [
{
title: '0-0-1-0',
key: '0-0-1-0',
},
{
title: '0-0-1-1',
key: '0-0-1-1',
},
{
title: '0-0-1-2',
key: '0-0-1-2',
},
],
},
{
title: '0-0-2',
key: '0-0-2',
},
],
},
{
title: '0-1',
key: '0-1',
children: [
{
title: '0-1-0-0',
key: '0-1-0-0',
},
{
title: '0-1-0-1',
key: '0-1-0-1',
},
{
title: '0-1-0-2',
key: '0-1-0-2',
},
],
},
{
title: '0-2',
key: '0-2',
},
];
The output should be : 15
The idea is to map trough all elements and if they have an array child, get the lentgh of it
I'm sure that I will go for a récursive function but it seems to be tricky..
I did'nt found any solutions in internet, have you an idea please ?
Thank you
function getLengthOfTreeData(treeData) {
let size = { size: 0 }; // object because it needs to be passed by reference
return getSize(size, treeData).size;
}
function getSize(size, treeData) { // recursive function
if (treeData.length === 0) {
return size;
}
size.size += treeData.length;
for (let i = 0; i < treeData.length; i++) {
const data = treeData[i];
if (data.children) getSize(size, data.children);
}
return size;
}
console.log(getLengthOfTreeData(treeData));
I have an example array
const array = [
{ obj: [{ fields: { title: 'titleValue1' } }, { fields: { title: 'titleValue2' } }] },
{ obj: [{ fields: { title: 'titleValue3' } }, { fields: { title: 'titleValue4' } }] },
]
I'm looking to modify the array to:
const modifiedArray = [
{ obj: [{ title: 'titleValue1' }, { title: 'titleValue2' }] },
{ obj: [{ title: 'titleValue3' }, { title: 'titleValue4' }] },
]
So when I loop over the modified array I can call 'obj.title' instead of 'obj.fields.title'
I think this can be achieved using .map. So far I have tried:
const ammendedArray = array.map(item => ({ ...item, title: item.map(e => e.fields) }))
But returning 'item.map is not a function'
Any help with this would be much appreciated.
In your code you are trying to use map for an item in the top level array. Which is like this for the first item,
{ obj: [{ fields: { title: 'titleValue1' } }, { fields: { title: 'titleValue2' } }] }
As you can see item is an object. You can not map through an object. What you can do is map through item.obj
const ammendedArray = array.map(item => ({ ...item, title: item.obj.map(e => e.fields) }))
But it will not solve your problem you will get a wrong array of objects like this,
[
{
obj: [{ fields: { title: 'titleValue1' } }, { fields: { title: 'titleValue2' } }],
title: [{ title: 'titleValue1' }, { title: 'titleValue2' }]
},
...
]
You will have to update the obj key instead. What you need to do is the following,
const array = [
{ obj: [{ fields: { title: 'titleValue1' } }, { fields: { title: 'titleValue2' } }] },
{ obj: [{ fields: { title: 'titleValue3' } }, { fields: { title: 'titleValue4' } }] },
]
const res = array.map((item) => {
return {
obj: item.obj.map(i => {
return i.fields
})
};
});
console.log(res);
I could reach to that like this :)
const array = [
{ obj: [{ fields: { title: 'titleValue1' } }, { fields: { title: 'titleValue2' } }] },
{ obj: [{ fields: { title: 'titleValue3' } }, { fields: { title: 'titleValue4' } }] },
]
// pass a function to map
const map1 = array.map((x)=>{
const filedsArray = [...x.obj]
x.obj = []
filedsArray.forEach((y)=>{
x.obj.push({title:y.fields.title})
})
return x
})
console.log(map1);
I have a nested Object array and I would like to remove an item out of this nested array, but for some reason this does not seem to work with my approach:
Object
export const completeNavigationItemsV2Response = [
{
id: 'Erlebniskategorien',
title: 'Erlebniskategorien',
uri: '/on/demandware.store/Sites-JSShop-Site/default/SearchJS-Show',
children: [
{
id: 'fliegen-fallen',
title: 'Fallen & Springen',
uri: '/fliegen-fallen/fallen-springen,default,sc.html',
children: [
{
id: 'fallen-springen',
title: 'Fallen & Springen',
uri: '/fliegen-fallen/fallen-springen,default,sc.html',
children: [],
}
],
},
{
id: 'Weit-Weg',
title: 'Reisen & Kurzurlaub',
uri: '/reisen/Weit-Weg,default,sc.html',
children: [
{
id: 'staedtereisen',
title: 'Städtereisen',
uri: '/reisen/staedtereisen,default,sc.html',
children: [],
}
],
},
{
id: 'motorpower',
title: 'Motorpower',
uri: '/geschenke-maenner/motorpower,default,sc.html',
children: [
{
id: 'rennwagen',
title: 'Rennwagen',
uri: '/motorpower/rennwagen,default,sc.html',
children: [],
}
],
},
{
id: '10',
title: 'Erlebnisse mit Stars',
uri: '/erlebnisse-mit-stars/l/10',
children: [
{ // <== remove this object with id === 'glossar'
id: 'glossar',
title: 'Glossar',
uri: '/erlebnisstandorte/glossar,default,pg.html',
children: [],
},
],
},
],
}
];
Does someone of you would now a handy es6 way how to remove that subObject from the whole object in a somewhat dynamic way like with the .map() or .filter() function?
If you want it for any level in your object, you could do it with a recursive function like so:
// Object is the same, just minified
const completeNavigationItemsV2Response=[{id:"Erlebniskategorien",title:"Erlebniskategorien",uri:"/on/demandware.store/Sites-JSShop-Site/default/SearchJS-Show",children:[{id:"fliegen-fallen",title:"Fallen & Springen",uri:"/fliegen-fallen/fallen-springen,default,sc.html",children:[{id:"fallen-springen",title:"Fallen & Springen",uri:"/fliegen-fallen/fallen-springen,default,sc.html",children:[]}]},{id:"Weit-Weg",title:"Reisen & Kurzurlaub",uri:"/reisen/Weit-Weg,default,sc.html",children:[{id:"staedtereisen",title:"Städtereisen",uri:"/reisen/staedtereisen,default,sc.html",children:[]}]},{id:"motorpower",title:"Motorpower",uri:"/geschenke-maenner/motorpower,default,sc.html",children:[{id:"rennwagen",title:"Rennwagen",uri:"/motorpower/rennwagen,default,sc.html",children:[]}]},{id:"10",title:"Erlebnisse mit Stars",uri:"/erlebnisse-mit-stars/l/10",children:[{id:"glossar",title:"Glossar",uri:"/erlebnisstandorte/glossar,default,pg.html",children:[]}]}]}];
const removeItemWithId = (array, id) => {
return array
.filter(obj => obj.id !== id) // filter out if the id matches
.map(obj => ({ // Do the same for children (if they exist)
...obj,
children: obj.children !== undefined
? removeItemWithId(obj.children, id)
: undefined
}));
};
console.log(removeItemWithId(completeNavigationItemsV2Response, 'glossar'));
Although newer than ES6, if you can support .flatMap(), you can do this recursively by calling .flatMap() on your initial array and then calling it on your children array. If you reach the element which you want to remove, you can return an empty array [], which will remove the object when concatenated into the resulting array.
const arr = [{ id: 'Erlebniskategorien', title: 'Erlebniskategorien', uri: '/on/demandware.store/Sites-JSShop-Site/default/SearchJS-Show', children: [{ id: 'fliegen-fallen', title: 'Fallen & Springen', uri: '/fliegen-fallen/fallen-springen,default,sc.html', children: [{ id: 'fallen-springen', title: 'Fallen & Springen', uri: '/fliegen-fallen/fallen-springen,default,sc.html', children: [], }], }, { id: 'Weit-Weg', title: 'Reisen & Kurzurlaub', uri: '/reisen/Weit-Weg,default,sc.html', children: [{ id: 'staedtereisen', title: 'Städtereisen', uri: '/reisen/staedtereisen,default,sc.html', children: [], }], }, { id: 'motorpower', title: 'Motorpower', uri: '/geschenke-maenner/motorpower,default,sc.html', children: [{ id: 'rennwagen', title: 'Rennwagen', uri: '/motorpower/rennwagen,default,sc.html', children: [], }], }, { id: '10', title: 'Erlebnisse mit Stars', uri: '/erlebnisse-mit-stars/l/10', children: [{ id: 'glossar', title: 'Glossar', uri: '/erlebnisstandorte/glossar,default,pg.html', children: [], }, ], }, ], }];
const removeId = "glossar";
const res = arr.flatMap(function fn(o) {
return o.id !== removeId ? ({...o, children: o.children.flatMap(fn)}) : [];
});
console.log(res);
I'm looking to filter my table recursively with the key "excludeInMenu". I can filter the first table but not the second content in "Items"
With this code
{routes.filter(route => !route.excludeInMenu)
Here is the Array I want to filter :
const routes: MenuRoute[] = [
{
key: 'invoice_show',
excludeInMenu: true
},
{
key: 'invoice_new'
},
{
key: 'template',
text: 'Template',
items: [
{
key: 'template_contract',
excludeInMenu: true
},
{
key: 'template_invoice'
}
]
}
];
I would like to filter it and get this as result :
[
{
key: 'invoice_new'
},
{
key: 'template',
text: 'Template',
items: [
{
key: 'template_invoice'
}
]
}
];
function filterItems(items){
return items.filter(item => !item.excludeInMenu)
}
filterItems(routes).forEach(route => {
if(route.items){
route.items = filterItems(route.items)
}
});
I'm trying to create a table and I have nested data like this:
[{
id: 24,
name: "DANIEL TSUTOMU OBARA",
number: "134",
phone: "11111111111",
rg: "4034092666",
EmployeeStatus: {
createdAt: "2019-08-07T14:38:52.576Z"
description: "Documentos rejeitados"
id: 3
updatedAt: "2019-08-07T14:38:52.576Z"
},
Sector: {
id: 2,
name: "Controladoria"
}
}]
And have this structure columns table:
columns: [
{ title: "Nome", field: "name" },
{ title: "CPF", field: "cpf" },
{ title: "Função", field: "FunctionId", lookup: {} },
{
title: "Setor",
field: "SectorId",
lookup: {}
},
{
title: "Status",
field: "EmployeeStatus", <------- I want to get description here
editable: "never"
}
],
Then, I need to pass these columns into my Material-table like this:
<MaterialTable
columns={state.columns}
data={state.data}
title=""
icons={tableIcons}
editable={{
onRowAdd: newData => createInstructor(newData),
onRowUpdate: async (newData, oldData) =>
updateInstructor(newData, oldData),
onRowDelete: oldData => deleteInstructor(oldData)
}}
/>
So, how I can do that access nested data into column field?
Thanks!
Please find the below solution.
I am expecting the data to have other objects too, so finding the first object with the key available.
let data = [{
id: 24,
name: "DANIEL TSUTOMU OBARA",
number: "134",
phone: "11111111111",
rg: "4034092666",
EmployeeStatus: {
createdAt: "2019-08-07T14:38:52.576Z",
description: "Documentos rejeitados",
id: 3,
updatedAt: "2019-08-07T14:38:52.576Z"
},
Sector: {
id: 2,
name: "Controladoria"
}
}]
let columns = [
{ title: "Nome", field: "name" },
{ title: "CPF", field: "cpf" },
{ title: "Função", field: "FunctionId", lookup: {} },
{
title: "Setor",
field: "SectorId",
lookup: {}
},
{
title: "Status",
field: "EmployeeStatus",
editable: "never"
}
];
let columnToUpdate = columns.find(obj => obj.title==="Status"); //find the column in columns array
let desc = data.find(obj => Object.keys(obj).includes('EmployeeStatus')).EmployeeStatus.description; // get description
columnToUpdate.field = desc; // mutate the object
console.log(columns);
I just decided to use lookup functionality and solve in this way for now.
const [state, setState] = useState({
columns: [
{ title: "ID", field: "id", editable: "never" },
{ title: "Nome", field: "name" },
{ title: "CPF", field: "cpf" },
{ title: "Função", field: "FunctionId", lookup: {} }, // 3
{
title: "Setor",
field: "SectorId",
lookup: {}
}, // 4
{
title: "Status",
field: "EmployeeStatusId",
lookup: {},
editable: "never"
}, // 5
]});
....
await api
.get(`/employee-status`)
.then(result => {
status = formatSectors(state, result, 5);
})
.....
const formatSectors = (state, result, position) => {
let columns = state.columns;
const indexColumnSector = 4;
columns[position].lookup = result.data.rows.reduce(
(accumulator, currentValue) => {
accumulator[currentValue.id] =
position === indexColumnSector
? currentValue.name
: currentValue.description;
return accumulator;
},
{}
);
return columns;
};