I am using Angular 13 and I have an array of objects like this:
[{
"name": "Operating System",
"checkedCount": 0,
"children": [{
"name": "Linux",
"value": "Redhat",
"checked": true
},
{
"name": "Windows",
"value": "Windows 10"
}
]
},
{
"name": "Software",
"checkedCount": 0,
"children": [{
"name": "Photoshop",
"value": "PS",
"checked": true
},
{
"name": "Dreamweaver",
"value": "DW"
},
{
"name": "Fireworks",
"value": "FW",
"checked": true
}
]
}
]
I would like to loop through the array, check if each object has a children
array and it in turn has a checked
property which is set to true
, then I should update the checkedCount
in the parent object. So, result should be like this:
[{
"name": "Operating System",
"checkedCount": 1,
"children": [{
"name": "Linux",
"value": "Redhat",
"checked": true
},
{
"name": "Windows",
"value": "Windows 10"
}
]
},
{
"name": "Software",
"checkedCount": 2,
"children": [{
"name": "Photoshop",
"value": "PS",
"checked": true
},
{
"name": "Dreamweaver",
"value": "DW"
},
{
"name": "Fireworks",
"value": "FW",
"checked": true
}
]
}
]
I tried to do it this way in angular, but this is in-efficient and results in an error saying this.allFilters[i].children[j]
may be undefined. So, looking for an efficient manner to do this.
for(let j=0;i<this.allFilters[i].children.length; j ) {
if (Object.keys(this.allFilters[i].children[j]).length > 0) {
if (Object.prototype.hasOwnProperty.call(this.allFilters[i].children[j], 'checked')) {
if(this.allFilters[i].children[j].checked) {
this.allFilters[i].checkedCount ;
}
}
}
}
CodePudding user response:
Use a nested for loop to check all the children. If checked
is truthy, increment the count of the parent. You don't need to check if parent.children
has any elements since if there are no elements the loop won't run anyways.
// minified data
const data = [{"name":"Operating System","checkedCount":0,"children":[{"name":"Linux","value":"Redhat","checked":!0},{"name":"Windows","value":"Windows 10"}]},{"name":"Software","checkedCount":0,"children":[{"name":"Photoshop","value":"PS","checked":!0},{"name":"Dreamweaver","value":"DW"},{"name":"Fireworks","value":"FW","checked":!0}]}];
for (const parent of data) {
for (const child of parent.children) {
if (child.checked) parent.checkedCount ;
}
}
console.log(data);
CodePudding user response:
You want to iterate over the items in an array, so let's use Array#forEach
and, for each item in the array, you want to update some property.
const input = []; // Your data here.
input.forEach(item => {
item.checkedCount = // ...
});
It looks like you want to aggregate the children
array into an integer by summing the number of checked
properties set to true
. Since we're aggregating on an array, let's use Array#reduce
. The function will take the value of the aggregation up to the current iteration (agg
), the item for the current iteration (cur
), and a default value for agg
(0
).
const input = []; // Your data here.
input.forEach(item => {
item.checkedCount = item.children.reduce((agg, cur) => {
// ...
}, 0);
});
Each iteration, we'll add to the aggregated value (agg
) if the current item's checked
field exists and is true.
const input = []; // Your data here.
input.forEach(item => {
item.checkedCount = item.children.reduce((agg, cur) => {
if (cur.checked) {
return agg 1;
} else {
return agg;
}
}, 0);
});
Putting it together and cleaning it up:
const input = [{name:"Operating System",checkedCount:NaN,children:[{name:"Linux",value:"Redhat",checked:!0},{name:"Windows",value:"Windows 10"}]},{name:"Software",checkedCount:NaN,children:[{name:"Photoshop",value:"PS",checked:!0},{name:"Dreamweaver",value:"DW"},{name:"Fireworks",value:"FW",checked:!0}]}];
input.forEach(item => {
item.checkedCount = item.children.reduce((agg, cur) => {
return cur.checked ? agg 1 : agg;
}, 0);
});
console.dir(input);
CodePudding user response:
Using filter
length
on children
array should do the job:
const data = [{"name":"Operating System","checkedCount":null,"children":[{"name":"Linux","value":"Redhat","checked":true},{"name":"Windows","value":"Windows 10"}]},{"name":"Software","checkedCount":null,"children":[{"name":"Photoshop","value":"PS","checked":true},{"name":"Dreamweaver","value":"DW"},{"name":"Fireworks","value":"FW","checked":true}]}];
data.forEach(itm => {
itm.checkedCount = itm.children?.filter(e => e.checked === true).length ?? 0;
});
console.log(input);
CodePudding user response:
No need to complicate it like that, you just need to check checked property in children.
data.forEach((v) => {
v.children.forEach((child) => {
if (child.checked) {
v.checkedCount ;
}
});
});
CodePudding user response:
I would suggest going functional.
Using map
const children = arr.map(obj => obj.children);
const result = children.map((child, idx) => {
const checkedCount = child.filter(obj => obj.checked)?.length;
return {
...arr[idx],
checkedCount
};
});
console.log(result)
or using forEach
const result = [];
const children = arr.map(obj => obj.children);
children.forEach((child, idx) => {
const checkedCount = child.filter(obj => obj.checked)?.length;
result[idx] = {
...arr[idx],
checkedCount
};
});
console.log(result)