I have an array of objects that looks like this:
[
{
"text":"Same but with checkboxes",
"opened": true,
"children":[
{
"text":"initially selected",
"opened":true
},
]
},
{
"text":"Same but with checkboxes",
"opened":true,
"children":[
{
"text":"initially open",
"opened":true,
"children":[
{
"text":"Another node",
"opened":true,
}
]
},
{
"text":"custom icon",
"opened":true,
},
{
"text":"disabled node",
"opened":true,
}
]
},
{
"text":"And wholerow selection",
"opened":true,
}
]
I want to know if it is possible to change the value for example of the key opened (to false) to all objects at all levels .. how can I do this?
I tried something like that without success
myArray.map(e => ({ ...e, opened: false }))
Make a recursive function - if the object being iterated over has a children array, call it for all such children.
const input=[{text:"Same but with checkboxes",opened:!0,children:[{text:"initially selected",opened:!0}]},{text:"Same but with checkboxes",opened:!0,children:[{text:"initially open",opened:!0,children:[{text:"Another node",opened:!0}]},{text:"custom icon",opened:!0},{text:"disabled node",opened:!0}]},{text:"And wholerow selection",opened:!0}];
const closeAll = (obj) => {
obj.opened = false;
obj.children?.forEach(closeAll);
};
input.forEach(closeAll);
console.log(input);
Recursion is here to help. Recursively search all the objects for opened key and switch it to false.
var data = [ { "text": "Same but with checkboxes", "opened": true, "children": [ { "text": "initially selected", "opened": true }, ] }, { "text": "Same but with checkboxes", "opened": true, "children": [ { "text": "initially open", "opened": true, "children": [ { "text": "Another node", "opened": true, } ] }, { "text": "custom icon", "opened": true, }, { "text": "disabled node", "opened": true, } ] }, { "text": "And wholerow selection", "opened": true, } ];
function run(data) {
for (let subData of data) {
if (subData["opened"])
subData["opened"] = false;
if (subData["children"])
run(subData["children"])
}
}
run(data)
console.log(data)
Just extend your map method to handle recursively. (children exist or not and Array or single object)
const updateOpened = (data) => {
if (Array.isArray(data)) {
return data.map(updateOpened);
}
const { children, ...item } = data;
return children
? { ...updateOpened(item), children: updateOpened(children) }
: { ...item, opened: true };
};
const arr=[{text:"Same but with checkboxes",opened:!0,children:[{text:"initially selected",opened:!0}]},{text:"Same but with checkboxes",opened:!0,children:[{text:"initially open",opened:!0,children:[{text:"Another node",opened:!0}]},{text:"custom icon",opened:!0},{text:"disabled node",opened:!0}]},{text:"And wholerow selection",opened:!0}];
console.log(updateOpened(arr));
Related
I have an object like this :
{
"roleId": "75f6af0f-a483-4ad1-af5f-5802887fe5e6",
"roleClaims": [
{
"type": "Permissions",
"value": "Permissions.Brands.View",
"selected": false
},
{
"type": "Permissions",
"value": "Permissions.Brands.Create",
"selected": false
},
{
"type": "Permissions",
"value": "Permissions.Dashboard.Create",
"selected": false
},
{
"type": "Permissions",
"value": "Permissions.Users.Create",
"selected": false
}
]
}
I want to re-organize the roleClaims array [ like each unique types objects (value = "Permissions.Brands.View" > Brands ) are separated array ] as mentioned below. And additionally add an extra property checkboxId (which value is unique number) to filtered object from the array of objects.
Is is really possible?
{
"roleId": "75f6af0f-a483-4ad1-af5f-5802887fe5e6",
"roleClaims": [
{
"valueId": "a8ca7eac-4f18-42d6-983f-44f6a8e157dc",
"valueType": "Brands",
"valueArray": [
{
"checkboxId": uuidv4(), // create new unique id
"type": "Permissions",
"value": "Permissions.Brands.View",
"selected": false
},
{
"checkboxId": uuidv4(),,
"type": "Permissions",
"value": "Permissions.Brands.Create",
"selected": false
}
]
},
{
"valueId": "a2566fd4-8763-41d4-881e-029851a440fd",
"valueType": "Dashboard",
"valueArray": [
{
"checkboxId": uuidv4(),,
"type": "Permissions",
"value": "Permissions.Dashboard.Create",
"selected": false
}
]
},
{
"valueId": "72328955-2bd2-469c-a094-be0bba383edd",
"valueType": "Users",
"valueArray": [
{
"checkboxId": uuidv4(),,
"type": "Permissions",
"value": "Permissions.Users.Create",
"selected": false
}
]
}
]
}
I tried with this :
const getRoleDetailsByRoleId = roleId => {
axios.get(`${urls.account.permissions.get_all_by_roleId}?roleId=${roleId}`).then(res => {
const permissionData = res.data;
const splitedValues = [];
permissionData.roleClaims.forEach(item => splitedValues.push(item.value.split('.')[1]));
const uniqueValues = [...new Set(splitedValues)];
const modifiePermissiondObj = {
roleId: permissionData.roleId,
roleClaims: uniqueValues.map(item => ({
valueId: uuidv4(),
valueType: item,
valueArray: permissionData.roleClaims.filter((fileredItem, index, arr) => fileredItem.value.split('.')[1] === item)
}))
};
setPermissions(modifiePermissiondObj);
setIsPageLoaded(true);
});
};
I have modified the roleClaims array but can't add the additional property.
If possible please help me.
const permissionData = {
"roleId": "75f6af0f-a483-4ad1-af5f-5802887fe5e6",
"roleClaims": [
{
"type": "Permissions",
"value": "Permissions.Brands.View",
"selected": false
},
{
"type": "Permissions",
"value": "Permissions.Brands.Create",
"selected": false
},
{
"type": "Permissions",
"value": "Permissions.Dashboard.Create",
"selected": false
},
{
"type": "Permissions",
"value": "Permissions.Users.Create",
"selected": false
}
]
}
const transformedPermissionData = permissionData.roleClaims.reduce((newOutput, role) => {
const extractedRole = role.value.split('.')[1];
const roleIndex = newOutput.roleClaims.findIndex(output => output && output.valueType === extractedRole)
if(roleIndex !== -1){
newOutput.roleClaims[roleIndex].valueArray.push({...role, checkboxId: 'UUID'})
}else {
newOutput.roleClaims.push({
valueId: 'UUID',
valueType: extractedRole,
valueArray: [{...role, checkboxId: 'UUID'}]
})
}
return newOutput
}, { roleId: permissionData.roleId, roleClaims: []})
console.log(transformedPermissionData)
You just need to map your valueArray like this:
valueArray: permissionData.roleClaims
.filter((fileredItem, index, arr) => fileredItem.value.split('.')[1] === item)
.map(value => ({...value, checkboxId: uuidv4()}))
My navigation gets the routes from the vue-router, so that I do not have to add them manually.
These routes have a meta boolean key called "inMenu", as well as their child routes. I only manage to filter the parent routes but not the child routes.
var res = this.$router.options.routes.filter(function f(o) {
if (o.route.meta.inMenu === true) return true
if (o.children) {
return (o.children = o.children.filter(f)).length
}
})
This is how I filter the parent routes but I can't manage it to filter the children.
return this.$router.options.routes.filter(route => route.meta.inMenu === true);
This is some sample data:
{
"path": "/orders",
"component": {
"name": "Orders",
"__file": "src/views/Orders.vue",
},
"meta": {
"icon": "fa-history",
"title": "Abwicklungen",
"inMenu": true
},
"children": [
{
"path": "list",
"name": "orderList",
"component": {
"name": "OrderList",
"__file": "src/views/orders/list.vue",
},
"meta": {
"title": "Bestellliste",
"icon": "fa-circle-o",
"inMenu": true
}
},
{
"path": "details/:id",
"name": "orderDetails",
"component": {
"name": "OrderDetails",
"__file": "src/views/orders/details.vue"
},
"meta": {
"title": "Bestellung",
"icon": "fa-circle-o",
"inMenu": false
}
},
{
"path": "dailyclosing",
"component": {
"name": "OrderList",
"__file": "src/views/orders/list.vue",
},
"meta": {
"title": "Tagesabschluss",
"icon": "fa-check",
"inMenu": true
}
}
]
}
I want to have each route and children not shown if inMenu is false.
Assuming you want all objects with true inMenu properties, you could build a new array with new children. Branches with no true inMenu items are filterd out.
function filter(array) {
return array.reduce((r, { children = [], ...o }) => {
children = filter(children);
if (o.meta.inMenu || children.length) r.push(Object.assign({}, o, children.length && { children }));
return r;
}, [])
}
var data = [{ path: "/orders", meta: { icon: "fa-history", title: "Abwicklungen", inMenu: true }, children: [{ path: "list", name: "orderList", meta: { title: "Bestellliste", icon: "fa-circle-o", inMenu: true } }, { path: "details/:id", name: "orderDetails", meta: { title: "Bestellung", icon: "fa-circle-o", inMenu: false } }, { path: "dailyclosing", meta: { title: "Tagesabschluss", icon: "fa-check", inMenu: true } }] }, { path: "/orders", meta: { icon: "fa-history", title: "Abwicklungen", inMenu: false }, children: [{ path: "list", name: "orderList", meta: { title: "Bestellliste", icon: "fa-circle-o", inMenu: true } }, { path: "details/:id", name: "orderDetails", meta: { title: "Bestellung", icon: "fa-circle-o", inMenu: false } }, { path: "dailyclosing", meta: { title: "Tagesabschluss", icon: "fa-check", inMenu: true } }] }],
result = filter(data);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
I am assuming:
You have multiple path objects inside an array.
Each path object contains a root level meta key and a children key.
If the inMenu value of the root meta key returns false, we filter out the whole object (which includes its children).
children doesn't contain any more children on its own .
So we apply reduce on the array, check whether the object's root inMenu is true and if so it will reconstruct itself while filtering its children. Filtering the children happens via the short helper function.
var data = [{"path":"/orders","component":{"name":"Orders","__file":"src/views/Orders.vue",},"meta":{"icon":"fa-history","title":"Abwicklungen","inMenu":!0},"children":[{"path":"list","name":"orderList","component":{"name":"OrderList","__file":"src/views/orders/list.vue",},"meta":{"title":"Bestellliste","icon":"fa-circle-o","inMenu":!0}},{"path":"details/:id","name":"orderDetails","component":{"name":"OrderDetails","__file":"src/views/orders/details.vue"},"meta":{"title":"Bestellung","icon":"fa-circle-o","inMenu":!1}},{"path":"dailyclosing","component":{"name":"OrderList","__file":"src/views/orders/list.vue",},"meta":{"title":"Tagesabschluss","icon":"fa-check","inMenu":!0}}]}];
const f = arr => arr.filter(o => o.meta.inMenu);
let res = data.reduce((a,c) => (c.meta.inMenu && a.push({...c, children: f(c.children)}), a),[]);
console.log(res)
Here is a working snippet. I think you just need to update your function in a way I have changed it. Of-course I have not use vue.js routes here. This is just a sample. You need to update according to your need. I think you'll get idea from here, about what is wrong in your function.
var data = [{
"path": "/orders",
"component": {
"name": "Orders",
"__file": "src/views/Orders.vue",
},
"meta": {
"icon": "fa-history",
"title": "Abwicklungen",
"inMenu": true
},
"children": [
{
"path": "list",
"name": "orderList",
"component": {
"name": "OrderList",
"__file": "src/views/orders/list.vue",
},
"meta": {
"title": "Bestellliste",
"icon": "fa-circle-o",
"inMenu": true
}
},
{
"path": "details/:id",
"name": "orderDetails",
"component": {
"name": "OrderDetails",
"__file": "src/views/orders/details.vue"
},
"meta": {
"title": "Bestellung",
"icon": "fa-circle-o",
"inMenu": false
}
},
{
"path": "dailyclosing",
"component": {
"name": "OrderList",
"__file": "src/views/orders/list.vue",
},
"meta": {
"title": "Tagesabschluss",
"icon": "fa-check",
"inMenu": true
}
}
]
}];
var res = data.filter(function f(o) {
if (o.children) {
return (o.children = o.children.filter(f)).length
}
if (o.meta.inMenu === true) return true;
return false;
})
console.log(res);
I have a nested object that I wish to retrieve certain key/value pairs from. For these to be retrieved they must have a value for each key.
I'm close, but I'm not getting any of the nested objects' key/value pairs.
I have created this fiddle
Here's the function I have at present:
function getKeysVals(obj, keys, recurse = false)
{
let addToOutput = true;
let out = [];
let cnt = 0;
obj.map
(
(thisObj) =>
{
let newObj = {}; // Temp holder for new object that gets added to output.
// Loop through the requested keys, adding them to the new object:
for( i in keys)
{
// Check that this key has a value:
if(!thisObj[keys[i]])
{
addToOutput = false;
break;
}
else
{
newObj[keys[i]] = thisObj[keys[i]];
}
}
// Ensure we have values for ALL the requested keys in this object:
if( addToOutput ) out.push(newObj);
// Go round again if this object has the specified recurse object:
if( thisObj[recurse] )
{
getKeysVals(thisObj[recurse], keys, recurse)
}
}
);
return out
}
When I call it with result = getKeysVals(nodes[0].nodes, ['id', 'text', 'filePath'], 'nodes'); I expect to get a new array with:
[
{ id: 1526297185466, text: 'test part a', filePath: 'test part a-1526297185451.CSV' },
{ id: 1526297202132, text: 'test part B', filePath: 'test part B-1526297202118.CSV' },
{ id: 1526297209980, text: 'Test Part C', filePath: 'Test Part C-1526297209966.CSV' }
]
But I only get:
[{ id: 1526297185466, text: 'test part a', filePath: 'test part a-1526297185451.CSV' }]
The whole object:
[{
"id": 1526297177970,
"text": "k",
"nodes": [
{
"id": 1526297185466,
"tags": [1],
"text": "test part a",
"state": { "checked": true, "expanded": true },
"filePath": "test part a-1526297185451.CSV"
},
{
"id": 1526297195199,
"tags": [1],
"text": "New Product Set",
"nodes": [
{
"id": 1526297202132,
"tags": [1],
"text": "test part B",
"state": { "checked": true, "expanded": true },
"filePath": "test part B-1526297202118.CSV"
},
{
"id": 1526297209980,
"tags": [1],
"text": "Test Part C",
"state": { "checked": true, "expanded": true },
"filePath": "Test Part C-1526297209966.CSV"
}
],
"state": { "checked": true }
}
],
"state": { "checked": true }
}]
If you call
getKeysVals(thisObj[recurse], keys, recurse)
This will create a new out and return that, so you may add that to the current out:
out.push(...getKeysVals(thisObj[recurse], keys, recurse));
This is my Array (http://www.jsoneditoronline.org/?id=cc51a12581667055781639b586fa6e15):
[
{
"documents": [
{
"name": "a",
"isSelected": true,
"status": "good"
},
{
"name": "b",
"isSelected": false,
"status": "good"
}
]
},
{
"documents": [
{
"name": "a",
"isSelected": true,
"status": "bad"
},
{
"name": "b",
"isSelected": false,
"status": "good"
}
]
},
{
"documents": [
{
"name": "a",
"isSelected": true,
"status": "verygood"
},
{
"name": "b",
"isSelected": false,
"status": "good"
}
]
},
{
"documents": [
{
"name": "a",
"isSelected": false,
"status": "good"
},
{
"name": "b",
"isSelected": false,
"status": "good"
}
]
}
]
I need to write condition using _.lodash.
This condition has to return TRUE if in array is at least one Selected document with Status other than good or verygood
Based on array from above.
http://prnt.sc/de3gx9
You can see on the screenshot that in array is an object with:
isSelected
Has other status than good or verygood
If in my Array is at least one object (with isSelected = true, and status = bad (or any other than good or verygood).
Then I want to see RESULT: TRUE
function checkStatusInArray() {
var data = [....]; // this is my array
var isDocumentSelectedWithWrongStatus = _.some(data, { isSelected: true, status: !"good" || !"verygood" });
// So if in array are some items with isSelected = true and status != good || verygood, then isDocumentSelectedWithWrongStatus = TRUE
return isDocumentSelectedWithWrongStatus;
}
You can do it without lodash - Array#some inside Array#some and a predicate (the predicate can be inlined as anonymous function), if the predicate returns, the result will be truthy:
function checkData(data, predicate) {
return data.some(function(item) {
return item.documents.some(predicate);
});
}
function predicate(document) {
return document.isSelected &&
!(document.status === 'good' ||
document.status === 'verygood');
}
function checkData(data, predicate) {
return data.some(function(item) {
return item.documents.some(predicate);
});
}
function predicate(document) {
return document.isSelected &&
!(document.status === 'good' ||
document.status === 'verygood');
}
var data = [{
"documents": [{
"name": "a",
"isSelected": true,
"status": "good"
}, {
"name": "b",
"isSelected": false,
"status": "good"
}]
}, {
"documents": [{
"name": "a",
"isSelected": true,
"status": "bad"
}, {
"name": "b",
"isSelected": false,
"status": "good"
}]
}, {
"documents": [{
"name": "a",
"isSelected": true,
"status": "verygood"
}, {
"name": "b",
"isSelected": false,
"status": "good"
}]
}, {
"documents": [{
"name": "a",
"isSelected": false,
"status": "good"
}, {
"name": "b",
"isSelected": false,
"status": "good"
}]
}];
var result = checkData(data, predicate);
console.log(result);
You could use lodash's flatMap to pluck the documents into one collection and then use some on the collection:
var data = [{"documents":[{"name":"a","isSelected":true,"status":"good"},{"name":"b","isSelected":false,"status":"good"}]},{"documents":[{"name":"a","isSelected":true,"status":"bad"},{"name":"b","isSelected":false,"status":"good"}]},{"documents":[{"name":"a","isSelected":true,"status":"verygood"},{"name":"b","isSelected":false,"status":"good"}]},{"documents":[{"name":"a","isSelected":false,"status":"good"},{"name":"b","isSelected":false,"status":"good"}]}]
var selectedButNotGood = function(document){
return document.isSelected &&
document.status != "good" &&
document.status != "verygood"
}
var result = _.chain(data)
.flatMap('documents')
.some(selectedButNotGood)
.value();
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.2/lodash.min.js"></script>
You can loop over them and create your own custom array.
var d = [{"documents":[{"name":"a","isSelected":true,"status":"good"},{"name":"b","isSelected":false,"status":"good"}]},{"documents":[{"name":"a","isSelected":true,"status":"bad"},{"name":"b","isSelected":false,"status":"good"}]},{"documents":[{"name":"a","isSelected":true,"status":"verygood"},{"name":"b","isSelected":false,"status":"good"}]},{"documents":[{"name":"a","isSelected":false,"status":"good"},{"name":"b","isSelected":false,"status":"good"}]}]
var statusList = ['good', 'verygood']
var r = d.some(function(o) {
return o.documents.filter(x => !statusList.includes(x.status) && x.isSelected).length > 0;
});
console.log(r)
I have a JavaScript object which looks like this:
{
"filters": [
{
"name": "Test",
"items": [
{
"id": 1207700620,
"checked": false
},
{
"id": 1207825584,
"checked": false
},
{
"id": 1207969166,
"checked": true
}
]
},
{
"name": "Empty",
"items": []
},
{
"name": "ThirdList",
"items": [
{
"id": "1207828314",
"checked": true
},
{
"id": "1236723086",
"checked": false
},
{
"id": "1208005603",
"checked": true
}
]
}
]
}
My object have a array by the name filters. This array contains multiple objects. Within each object there is an array by name items. For each element in this items array, I need to check the checked property & if it is false, I need to delete that record (that item in items array).
I need to ensure IE 8 compatability.
I can use a for loop on filters array and within this for loop I can use another for loop to go over items array. I dont want this apporach.
Is there smarter way to achieve this by lodash or jquery or any other JavaScript library??
You can try a combination of forEach and filter methods:
obj.filters.forEach(function(filter) {
filter.items = filter.items.filter(function(el) {
return el.checked;
});
});
Check example below.
var obj = {
"filters": [
{
"name": "Test",
"items": [
{
"id": 1207700620,
"checked": false
},
{
"id": 1207825584,
"checked": false
},
{
"id": 1207969166,
"checked": true
}
]
},
{
"name": "Empty",
"items": []
},
{
"name": "ThirdList",
"items": [
{
"id": "1207828314",
"checked": true
},
{
"id": "1236723086",
"checked": false
},
{
"id": "1208005603",
"checked": true
}
]
}
]
};
obj.filters.forEach(function(filter) {
filter.items = filter.items.filter(function(el) {
return el.checked;
});
});
alert( JSON.stringify(obj, null, 4) );
For IE8 compatibility you can use polyfills or ES5 shims.
Another option if you can use Underscore/Lo-Dash, you can go with analog methods: _.each and _.filter instead of Array.prototype.forEach and Array.prototype.filter:
_.each(obj.filters, function(filter) {
filter.items = _.filter(filter.items, function(el) {
return el.checked;
});
});