How to update nested object array in js? - javascript

I need to modify component state which has inner array objects. There is no problem with modifying object array but I'd like to update inner object array value which has action format. It doesn't update the action value as "No Action Needed".
What's the wrong with that map() functions?
Thanks in advance.
let example_response = {
data: [
{
details: [
{
format: "date",
value: "2020-04-29T15:03:44.871Z",
title: "Date"
},
{
format: "action",
value: "-",
title: "Action"
}
],
id: 13409,
isSelected:true
}, {
details: [
{
format: "date",
value: "2019-04-29T15:03:44.871Z",
title: "Date"
},
{
format: "action",
value: "-",
title: "Action"
}
],
id: 13409,
isSelected:false
}
]
};
const newList = example_response.data.map((item) => {
if (item.isSelected) {
item.details.map((elem) => {
if (elem.format === "action") {
const updatedElem = {
...elem,
value: "No Action Needed"
};
return updatedElem;
}
});
}
return item;
});
console.log(newList);

I found 2 problems:
You are not modifying item.details (you are just mapping it).
You only return updatedElem when elem.format === "action" but you're returning anything otherwise
Try
let example_response = {
data: [{
details: [{
format: "date",
value: "2020-04-29T15:03:44.871Z",
title: "Date"
},
{
format: "action",
value: "-",
title: "Action"
}
],
id: 13409,
isSelected: true
}, {
details: [{
format: "date",
value: "2019-04-29T15:03:44.871Z",
title: "Date"
},
{
format: "action",
value: "-",
title: "Action"
}
],
id: 13409,
isSelected: false
}]
};
const newList = example_response.data.map((item) => {
if (item.isSelected) {
item.details = item.details.map((elem) => {
if (elem.format === "action") {
elem.value = "No Action Needed";
}
return elem;
});
}
return item;
});
console.log(newList);

Since you're already creating a new array with the top level map method, you can use forEach and assign the value.
let example_response = {
data: [
{
details: [
{
format: "date",
value: "2020-04-29T15:03:44.871Z",
title: "Date"
},
{
format: "action",
value: "-",
title: "Action"
}
],
id: 13409,
isSelected:true
}, {
details: [
{
format: "date",
value: "2019-04-29T15:03:44.871Z",
title: "Date"
},
{
format: "action",
value: "-",
title: "Action"
}
],
id: 13409,
isSelected:false
}
]
};
const newList = example_response.data.map((item) => {
if (item.isSelected) {
item.details.forEach((elem) => {
if (elem.format === "action") {
elem.value = "No Action Needed";
}
});
}
return item;
});
console.log(newList);

let example_response = {
data: [{
details: [{
format: "date",
value: "2020-04-29T15:03:44.871Z",
title: "Date"
},
{
format: "action",
value: "-",
title: "Action"
}
],
id: 13409,
isSelected: true
},
{
details: [{
format: "date",
value: "2019-04-29T15:03:44.871Z",
title: "Date"
},
{
format: "action",
value: "-",
title: "Action"
}
],
id: 13409,
isSelected: false
}
]
};
const newList = example_response.data.map(item => item.isSelected
? item.details.map(elem => elem.format === "action"
? ({ ...elem, value: "No Action Needed" })
: elem)
: item.details);
console.log(newList);

Your code does not return a modified item, it just maps over the details when the item is selected. Make sure you are returning something in else clauses too. Here's an example using shorthand notation:
const elementUpdater = (element) => element.format === 'action' ? {...element, value: 'No action needed'} : element
const itemDetailsUpdater = (item) => item.isSelected ? item.details.map(elementUpdater) : item
example_response.data.map(itemDetailsUpdater)
Which yields:
[
[
{
"format": "date",
"value": "2020-04-29T15:03:44.871Z",
"title": "Date"
},
{
"format": "action",
"value": "No action needed",
"title": "Action"
}
],
{
"details": [
{
"format": "date",
"value": "2019-04-29T15:03:44.871Z",
"title": "Date"
},
{
"format": "action",
"value": "-",
"title": "Action"
}
],
"id": 13409,
"isSelected": false
}
]

Related

How know the value of property of object in javascript?

I have this object:
var x= {
"data": {
"getLand": {
"id": "xxx",
"bid": [{
"result": "ON",
"buyer": {
"username": "Dis"
},
"offerSet": [{
"createdStr": "202",
"value": 1
}]
},
{
"result": "CANCEL",
"buyer": {
"username": "Dis"
},
"offerSet": [{
"createdStr": "202",
"value": 15
}]
}
]
}
}
}
How can i know is result === "ON" && username == "Dis" ?
I tried with this:
for (var key in x.data.getLand.bid) {
if((x.data.getLand.bid[key].result === 'ON') && (x.data.getLand.bid[key].buyer.username.toUpperCase() === 'DIS')){
console.log(x.data.getLand.bid[key]);
}
}
it gives me some problems .... sometimes it works and sometimes it doesn't. Would you be kind enough to show me another way?
You can utilize the ES6 array function forEach to loop through the array items.
const x = { data: { getLand: { id: "xxx", bid: [ { result: "ON", buyer: { username: "Dis", }, offerSet: [ { createdStr: "202", value: 1, }, ], }, { result: "CANCEL", buyer: { username: "Dis", }, offerSet: [ { createdStr: "202", value: 15, }, ], }, ], }, }, }
const bidList = x.data.getLand.bid
bidList.forEach((bid, index) => {
if (bid.result === 'ON' && bid.buyer.username.toUpperCase() === 'DIS') console.log(index, bid)
})
You can do this with filter and forEach loop.
like this:
var x = { data: { getLand: { id: "xxx", bid: [ { result: "ON", buyer: { username: "Dis" }, offerSet: [{ createdStr: "202", value: 1 }] }, { result: "CANCEL", buyer: { username: "Dis" }, offerSet: [{ createdStr: "202", value: 15 }] } ] } } };
x.data.getLand.bid
.filter(
({ result, buyer: { username } }) => result === "ON" || username === "Dis"
)
.forEach((el, id) => console.log(el, id));
An example with for...of
var x = { data: { getLand: { id: "xxx", bid: [ { result: "ON", buyer: { username: "Dis", }, offerSet: [ { createdStr: "202", value: 1, }, ], }, { result: "CANCEL", buyer: { username: "Dis", }, offerSet: [ { createdStr: "202", value: 15, }, ], }, ], }, }, };
for (const item of x.data.getLand.bid) {
if (item.result === "ON" && item.buyer.username.toUpperCase() === "DIS") {
console.log(item);
}
}
Edit:
If you need the index, you can use forEach.
var x = { data: { getLand: { id: "xxx", bid: [ { result: "ON", buyer: { username: "Dis", }, offerSet: [ { createdStr: "202", value: 1, }, ], }, { result: "CANCEL", buyer: { username: "Dis", }, offerSet: [ { createdStr: "202", value: 15, }, ], }, ], }, }, };
x.data.getLand.bid.forEach((item, i) => {
if (item.result === "ON" && item.buyer.username.toUpperCase() === "DIS") {
console.log(i);
console.log(item);
}
});

Create csv out of array of objects with nested array of objects javascript

So I'm trying to take these two pieces of data
const headers = [
{ label: 'Item/Passage', key: 'objectType' },
{ label: 'Constraint Type', key: 'constraintType' },
{ label: 'Constraint Name', key: 'description' },
{ label: 'Lower', key: 'lowerBound' },
{ label: 'Upper', key: 'upperBound' },
{ label: 'Target Attribute', key: 'attributeName' },
{ label: 'Theta', key: 'referenceValue' },
{ label: 'Form/Passage', key: 'scope' },
{ label: 'Filter', key: 'filters' },
{ label: 'Filter values', key: 'filterValues' },
{ label: 'Min', key: 'min' },
{ label: 'Max', key: 'max' },
];
const array = [
{
"objectType": "Item",
"constraintType": "Include",
"description": "constraint1",
"lowerBound": "1",
"filters": [
{
"attributeName": "Item Identifier",
"values": "I105_15201|I105_15202",
"valueLowerBound": null,
"valueUpperBound": null
},
{
"attributeName": "Passage Item Order",
"values": "5|1|3|4|6|7|8|9|10|11|12|13|14|15|16|None",
"valueLowerBound": null,
"valueUpperBound": null
}
],
"upperBound": "4",
"attributeName": null,
"referenceValue": "",
"scope": null
},
{
"objectType": "Passage",
"constraintType": "Include",
"description": "constraint2",
"lowerBound": "1",
"filters": [
{
"attributeName": "Passage Identifier",
"values": "pid_1-1|pid_10-1|pid_2-1|pid_4-1|pid_5-1|pid_7-1|pid_8-1|pid_9-1",
"valueLowerBound": null,
"valueUpperBound": null
},
{
"attributeName": "Word Count",
"values": "",
"valueLowerBound": 3,
"valueUpperBound": 234
}
],
"upperBound": "4",
"attributeName": null,
"referenceValue": "",
"scope": null
},
{
"objectType": "Item",
"constraintType": "Include",
"description": "constraint3",
"filters": [],
"lowerBound": "1",
"upperBound": "4",
"attributeName": null,
"referenceValue": "",
"scope": null
}
]
And produce a csv file that looks like this,
Basically, I take the label values from the header array, create the header, then each constraint is put on its own row. If a constraint has filters, another row is created and the values are placed within the last four columns. For example, constraint1 and 2 have two filters, constraint 3 has none.
I've been able to accomplish already with the following code, but feel it's not a terribly stable implementation. Looking for any suggestions on how to implement this. Thanks!
Here is the copy of the string I've been able to create
toCsv -> csv Item/Passage,Constraint Type,Constraint Name,Lower,Upper,Target Attribute,Theta,Form/Passage,Filter,Filter values,Min,Max
Item,Include,constraint1,1,4,,,
,,,,,,,,Item Identifier,I105_15201|I105_15202,,
,,,,,,,,Passage Item Order,5|1|3|4|6|7|8|9|10|11|12|13|14|15|16|None,,
Passage,Include,constraint2,1,4,,,
,,,,,,,,Passage Identifier,pid_1-1|pid_10-1|pid_2-1|pid_4-1|pid_5-1|pid_7-1|pid_8-1|pid_9-1,,
,,,,,,,,Word Count,,3,234
Item,Include,constraint3,1,4,,,
export const toCsv = (array, headers) => {
const getValuesFromObject = (obj) => {
if (typeof obj !== 'object' || obj === null) {
return [];
}
const headerKeys = Object.keys(headers);
const keys = Object.keys(obj);
const values = [];
const filterValues = [];
for (var i = 0; i < keys.length; ++i) {
if (Array.isArray(obj[keys[i]])) {
obj[keys[i]].map((filterObj) => {
filterValues.push(',,,,,,,,' + Object.values(filterObj)); // this part bothers me the most. I use it to create empty cells for the filter rows.
});
} else {
values.push(obj[keys[i]]);
}
}
return [].concat([values]).concat(filterValues).join('\n');
};
const csvHeaders = headers.map((obj) => obj.label).join(',');
const body = array.map(getValuesFromObject);
let csv = [].concat([csvHeaders]).concat(body).join('\n');
return csv;
};
You could take a single loop for the objects, their filters and iterate the keys.
const
toCsv = (array, headers) => {
const getValuesFromObject = o => !o || typeof o !== 'object'
? []
: [
headers.map(({ key }) => key !== 'filters' && o[key] || '').join(),
...o.filters.map(q => headers.map(({ key }) => q[key] || '').join())
];
return [
headers.map((obj) => obj.label).join(','),
...array.flatMap(getValuesFromObject)
].join('\n');
},
headers = [{ label: 'Item/Passage', key: 'objectType' }, { label: 'Constraint Type', key: 'constraintType' }, { label: 'Constraint Name', key: 'description' }, { label: 'Lower', key: 'lowerBound' }, { label: 'Upper', key: 'upperBound' }, { label: 'Target Attribute', key: 'attributeName' }, { label: 'Theta', key: 'referenceValue' }, { label: 'Form/Passage', key: 'scope' }, { label: 'Filter', key: 'filters' }, { label: 'Filter values', key: 'values' }, { label: 'Min', key: 'valueLowerBound' }, { label: 'Max', key: 'valueUpperBound' }],
array = [{ objectType: "Item", constraintType: "Include", description: "constraint1", lowerBound: "1", filters: [{ attributeName: "Item Identifier", values: "I105_15201|I105_15202", valueLowerBound: null, valueUpperBound: null }, { attributeName: "Passage Item Order", values: "5|1|3|4|6|7|8|9|10|11|12|13|14|15|16|None", valueLowerBound: null, valueUpperBound: null }], upperBound: "4", attributeName: null, referenceValue: "", scope: null }, { objectType: "Passage", constraintType: "Include", description: "constraint2", lowerBound: "1", filters: [{ attributeName: "Passage Identifier", values: "pid_1-1|pid_10-1|pid_2-1|pid_4-1|pid_5-1|pid_7-1|pid_8-1|pid_9-1", valueLowerBound: null, valueUpperBound: null }, { attributeName: "Word Count", values: "", valueLowerBound: 3, valueUpperBound: 234 }], upperBound: "4", attributeName: null, referenceValue: "", scope: null }, { objectType: "Item", constraintType: "Include", description: "constraint3", filters: [], lowerBound: "1", upperBound: "4", attributeName: null, referenceValue: "", scope: null }],
result = toCsv(array, headers);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Update array of objects based on the object passed

I have an array of objects that has the following format,
const options = [
{ key: 1, text: "Name", value: "name", icon: "sort" },
{ key: 2, text: "Time", value: "time", icon: "sort" },
{ key: 3, text: "Type", value: "type", icon: "sort" }
];
Now based on the input passed which of format {fieldName,order} I have to modify the array. Basically order will take two values "asc" or "desc" and the fieldName will take any of the values in the value property of options array.
For Example : { fieldName: "name", order : "asc"} or { fieldName: "type", order: "desc"}
Now basically based this order , I have modify the icon field of the source array for that field.
If order is asc, then change the icon property for that field to sort up .If its order is desc, then change the icon property for that field to sort down
Example
1) sortBy: { fielName: "name", order:"asc"}
//Output
[
{ key: 1, text: "Name", value: "name", icon: "sort up" },
{ key: 2, text: "Time", value: "time", icon: "sort" },
{ key: 3, text: "Type", value: "type", icon: "sort" }
];
2) sortBy: { fielName: "type", order:"desc"}
//Output
[
{ key: 1, text: "Name", value: "name", icon: "sort" },
{ key: 2, text: "Time", value: "time", icon: "sort" },
{ key: 3, text: "Type", value: "type", icon: "sort down"}
];
It should update icon only of the field passed to it, and rest fields icon should be set to "sort"
This is what I tried
const options = [
{ key: 1, text: "Name", value: "name", icon: "sort" },
{ key: 2, text: "Time", value: "time", icon: "sort" },
{ key: 3, text: "Type", value: "type", icon: "sort" }
];
function updateArray(obj)
{
const newArr = options.map(item => {
if(item.name === obj.fieldName) {
return {...item, icon: obj.order === "desc" ? "sort-desc" :"sort-asc" };
}
return {...item};
});
return newArr;
}
Try this
const options = [
{ key: 1, text: "Name", value: "name", icon: "sort" },
{ key: 2, text: "Time", value: "time", icon: "sort" },
{ key: 3, text: "Type", value: "type", icon: "sort" }
];
function sorta(op,options){
field =op.fielName
newarray=[]
options.forEach(o=>{
if(o.value==field){
op.order=="asc"?f="up":f="down"
o.icon="sort-"+f
newarray.push(o)
}
else newarray.push(o)
})
return newarray
}
console.log(sorta({ fielName: "name", order:"asc"},options ))
Your function works, but you are trying to access a non-existent property.
I believe it should be:
if(item.value === obj.fieldName) {
...
}
Demo:
const options = [
{ key: 1, text: "Name", value: "name", icon: "sort" },
{ key: 2, text: "Time", value: "time", icon: "sort" },
{ key: 3, text: "Type", value: "type", icon: "sort" }
];
function updateArray(obj)
{
const newArr = options.map(item => {
if(item.value === obj.fieldName) {
return {...item, icon: obj.order === "desc" ? "sort-desc" :"sort-asc" };
}
return {...item};
});
return newArr;
};
console.log(updateArray({fieldName: 'type', order: 'desc'}));
console.log(updateArray({fieldName: 'time', order: 'asc'}));
console.log(updateArray({fieldName: 'name', order: 'desc'}));

How to filtering between array of sub arrays and array of sub arrays in javascript?

I have got two arrays of objects. I want to filter data based on PermissionObj.
This is coming from database. Here are arrays of sub-arrays in the permissionObj.
const PermissionObj = {
permission: [
{
books: [
{
label: "Can View",
value: "can_view"
}
]
},
{
Journals: [
{
label: "Can View",
value: "can_view"
},
{
label: "Can Create",
value: "can_create"
}
]
},
{
deal: [
{
label: "Can update",
value: "can_update"
},
{
label: "Can delete",
value: "can_delete"
}
]
}
]
}
this is static data. I want to compare this data based on PermissionObj.
const data = [
{
label: "books",
value: "can_view"
},
{
label: "deal",
content: [
{
value: "can_update"
},
{
value: "can_delete"
},
{ value: "can_view" }
]
},
{
label: "Articles"
},
{
label: "Journals",
content: [
{
value: "can_create"
},
{
value: "can_view"
},
{
value: "can_delete"
},
{
value: "can_edit"
}
]
}
]
I am trying to filter the data array of the object based on PermissionObj array of objects. here is my trying code.
const permKeys = PermissionObj.permission.flatMap(item => Object.keys(item));
const filteredData = data.filter(({ label }) => permKeys.includes(label));
console.log(filteredData);
Here is my problem, I have been faced is that I don't want to get can_edit, can_delete if it doesn't match with permission objects in journals. In my permission objects, There is no can_edit and can_delete in journals.
My accepted Output would be this format :
const data = [
{
label: "books",
value: "can_view"
},
{
label: "deal",
content: [
{
value: "can_update"
},
{
value: "can_delete"
}
]
},
{
label: "Journals",
content: [
{
value: "can_create"
},
{
value: "can_view"
}
]
}
]
It is possible to use reduce method and apply logic to decide what data should be pushed:
const result = data.reduce((a, c) => {
let filterObj = PermissionObj.permission.find(f => f[c.label]);
if (filterObj) {
if (c.value) {
a.push(c);
}
if (c.content) {
c.content = c.content.filter(f => filterObj[c.label]
.some(s => s.value.toLowerCase() == f.value.toLowerCase()));
a.push(c);
}
}
return a;
},[])
An example:
const PermissionObj = {
permission: [
{
"books": [
{
"label": "Can View",
"value": "can_view"
}
]
},
{
"Journals": [
{
"label": "Can View",
"value": "can_view"
},
{
"label": "Can Create",
"value": "can_create"
}
]
},
{
"deal": [
{
"label": "Can update",
"value": "can_update"
},
{
"label": "Can delete",
"value": "can_delete"
}
]
}
]
};
const data = [
{
label: "books",
value: "can_view"
},
{
label: "deal",
content: [
{
value: "can_update"
},
{
value: "can_delete"
},
{
value:"can_view"
}
]
},
{
label: "Articles",
},
{
label: "Journals",
content: [
{
value: "can_create"
},
{
value: "can_view"
},
{
value: "can_delete"
},
{
value: "can_edit"
}
]
}
];
const result = data.reduce((a, c) => {
let filterObj = PermissionObj.permission.find(f => f[c.label]);
if (filterObj) {
if (c.value) {
a.push(c);
}
if (c.content) {
c.content = c.content.filter(f => filterObj[c.label].some(s => s.value.toLowerCase() == f.value.toLowerCase()));
a.push(c);
}
}
return a;
},[])
console.log(result);

Setting array keys dynamically based on length

Given an array in this format:
[
[{
name: "name",
value: "My-name"
},
{
name: "qty",
value: "1"
},
{
name: "url",
value: "test.com"
},
{
name: "comment",
value: "my-comment"
}
],
[{
name: "name",
value: "My-name2"
},
{
name: "qty",
value: "3"
},
{
name: "url",
value: "test2.com"
}
],
[{
name: "name",
value: "My-name3"
},
{
name: "qty",
value: "1"
},
{
name: "url",
value: "test3.com"
},
{
name: "comment",
value: "my-comment3"
}
]
]
I'm looking to switch that to:
[
[
{ name: "My-name" },
{ qty: "1" },
{ url: "test.com" },
{ comment: "my-comment", }
],[
{ name: "My-name2" },
{ qty: "3" },
{ url: "test2.com",
],[
{ name: "My-name3", },
{ qty: "1", },
{ url: "test3.com", },
{ comment: "my-comment3", }
]
]
In other words, swapping out the array keys but maintaining the object structure within each array element.
I've tried looping over each element and can swap the keys out using something like:
newArray[iCount][item.name] = item.value;
However I'm then struggling to preserve the object order. Note that the comment field may or may not appear in the object.
With Array.map() function:
var arr = [
[{name:"name",value:"My-name"},{name:"qty",value:"1"},{name:"url",value:"test.com"},{name:"comment",value:"my-comment"}],
[{name:"name",value:"My-name2"},{name:"qty",value:"3"},{name:"url",value:"test2.com"}],
[{name:"name",value:"My-name3"},{name:"qty",value:"1"},{name:"url",value:"test3.com"},{name:"comment",value:"my-comment3"}]
],
result = arr.map(function(a){
return a.map(function(obj){
var o = {};
o[obj.name] = obj.value
return o;
});
});
console.log(result);
Check my moreBetterOutput value. I think will be better.
If you still need a result like your example in the question then you can check output value.
const input = [
[
{
name:"name",
value:"My-name"
},
{
name:"qty",
value:"1"
},
{
name:"url",
value:"test.com"
},
{
name:"comment",
value:"my-comment"
}
],
[
{
name:"name",
value:"My-name2"
},
{
name:"qty",
value:"3"
},
{
name:"url",
value:"test2.com"
}
],
[
{
name:"name",
value:"My-name3"
},
{
name:"qty",
value:"1"
},
{
name:"url",
value:"test3.com"
},
{
name:"comment",
value:"my-comment3"
}
]
]
const output = input.map(arr => arr.map(obj => ({[obj.name]: obj.value})))
const moreBetterOutput = output.map(arr => arr.reduce((acc, item, index) => {
acc[Object.keys(item)[0]] = item[Object.keys(item)[0]];
return acc;
}, {}) )
//console.log(output);
console.log(moreBetterOutput);
Another map function:
const result = array.map( subarray =>
Object.assign(...subarray.map( ({name, value}) => ({ [name] : value }) ))
);

Categories

Resources