i have object structure like this,
[{
"id":"8661c8c96df94ac78283360e0d1c86bd",
"modifiedObject":{....},
"originalObject":{...}
},
{
"id":"1525drd616dr17d78283360e0d1c86bd",
"modifiedObject":null,
"originalObject":{...}
},
{
"id":"6767srsr14542525276767cbd246464",
"modifiedObject":{....},
"originalObject":null
}]
I am finding an object with the id and get the inner object(if modified object present if not original object) and then modifying the data using below code
const originalCopyObject = projObjs.find(s => s.id === projectObjectId);
const targetCopyObject = originalCopyObject.modifiedObject || originalCopyObject.originalObject; // here in this case it always be one either modified or original object
const targetMutatedCopyObject = cloneDeep(targetCopyObject);
if (!targetMutatedCopyObject?.glazingOrGasMaterials.length) {
targetMutatedCopyObject.glazingOrGasMaterials = [
...targetMutatedCopyObject.glazingGasMaterials,
...targetMutatedCopyObject.glazingSimpleMaterials,
];
}
targetMutatedCopyObject.opaqueConstructions.forEach(transformConstructions);
Now targetMutatedCopyObject is having one of the modifiedObject or originalObject, How can I replace this targetMutatedCopyObject object in projObjs.
Could any one please let me know how to replace this tragetMutatedCopyObject in projObjs array of objects.
Many thanks in advance.
Updated Code :
projObjs.map(projObj => {
if (projObj.id === projectObjectId) {
const targetCopyObject = projObj.modifiedObject || projObj.originalObject;
const mutatedCopyObject = transformFormStateToMutationObject(targetCopyObject);
if (projObj.modifiedObject) {
return {
...projObj,
modifiedObject: mutatedCopyObject
};
}
if (projObj.originalObject) {
return {
...projObj,
originalObject: mutatedCopyObject
};
}
return projObj;
}
return projObj;
});
}`
Generally you would copy, or map, the old object to a new object reference. If the id matches the currently mapped element, return new object with the updated/modified properties, otherwise return the current element.
projObjs.map((projObj) => {
if (projObj.id === projectObjectId) {
const targetCopyObject = projObj.modifiedObject || projObj.originalObject;
const targetMutatedCopyObject = cloneDeep(targetCopyObject);
if (!targetMutatedCopyObject?.glazingOrGasMaterials.length) {
targetMutatedCopyObject.glazingOrGasMaterials = [
...targetMutatedCopyObject.glazingGasMaterials,
...targetMutatedCopyObject.glazingSimpleMaterials
];
}
targetMutatedCopyObject.opaqueConstructions.forEach(transformConstructions);
return {
...projObj,
modifiedObject: targetCopyObject
};
}
return projObj;
});
Edit to return updated objects back into their original object keys
Factor the object update logic into a utility function and apply some branching logic on the modifiedObject and originalObject values in order to return an updated object back to the appropriate key.
projObjs.map((projObj) => {
if (projObj.id === projectObjectId) {
const updateObject = (targetCopyObject) => {
const targetMutatedCopyObject = cloneDeep(targetCopyObject);
if (!targetMutatedCopyObject?.glazingOrGasMaterials.length) {
targetMutatedCopyObject.glazingOrGasMaterials = [
...targetMutatedCopyObject.glazingGasMaterials,
...targetMutatedCopyObject.glazingSimpleMaterials
];
}
targetMutatedCopyObject.opaqueConstructions.forEach(
transformConstructions
);
return targetMutatedCopyObject;
};
if (projObj.modifiedObject) {
return {
...projObj,
modifiedObject: updateObject(projObj.modifiedObject)
};
}
if (projObj.originalObject) {
return {
...projObj,
originalObject: updateObject(projObj.originalObject)
};
}
return projObj;
}
return projObj;
});
Note: Be sure to capture the returned result from projObjs.map to update any parent object. This will be the new updated array.
Related
I'm working on the react-native project and I have an array object which is coming from backend.
here is the sample of an Array.
{
"2010":[
{
"id":1243,
"eventName":"sample_01",
"categoryType":"CUSTOM_NOTES",
"tags":"tag19",
"lastModified":"2022-10-04T14:31:32Z",
"attachments":[
]
}
],
"2022":[
{
"id":1244,
"eventName":"sample_02",
"categoryType":"CUSTOM_NOTES",
"tags":"tag1, tag12, tag3, tag52, tag19",
"lastModified":"2022-10-04T14:31:32Z",
"attachments":[
]
},
{
"id":1245,
"eventName":"hello_03",
"categoryType":"CUSTOM_NOTES",
"tags":"tag1, tag12",
"lastModified":"2022-10-04T14:31:32Z",
"attachments":[
]
}
]
}
In this array, it has some tags which were provided by the user previously (ex: "tags":"tag1, tag12").
There can be multiple or single tags in the array object. Using those tags or tags user should be able to filter the items in the array.
But my code is not working for the above behavior and it filters the elements with a tag, which is selected at last by the user.
Please help me to find an answer. Thanks in advance.
My code for the filtering as follows.
FilterByTagsOrAttachements = (advancedFilterData) => {
let advancedFilterFn = {};
if (advancedFilterData[0].filterType === "Tag") {
for (let advancedItem of advancedFilterData) {
for (const itemTag of advancedItem.data) {
advancedFilterFn = (a) => {
for (let tag of a.tags.split(',')) {
return isEqual(tag, itemTag);
}
};
}
}
} else if (advancedFilterData[1].filterType === "Attachments") {
console.log(JSON.stringify(advancedFilterData[1].data));
}
this.onCreateAdvancedFilterObject(advancedFilterFn);
}
onCreateAdvancedFilterObject = (advancedFilterFn) => {
this.setState(state => {
const events = {};
for (const [year, items] of Object.entries(state.events)) {
events[year] = items.slice().filter(advancedFilterFn);
}
return { events }
})
}
and advancedFilterData array is as follws.
advancedFilterData => [{"filterType":"Tag","data":["tag1","tag12"]},{"filterType":"Attachments","data":[]}]
I guess you need to store all the filters inside an array and then use this array to check if it includes all the elements. Also, since you have , , you should split with , unless you handle it accordingly inside your isEqual method.
FilterByTagsOrAttachements = (advancedFilterData) => {
let advancedFilterFn = {};
let filterArray = []
if (advancedFilterData[0].filterType === "Tag") {
for (let advancedItem of advancedFilterData) {
filterArray = filterArray.concat(advancedItem.data)
}
advancedFilterFn = (a) => {
for (let tag of a.tags.split(', ')) {
return filterArray.includes(tag);
}
};
} else if (advancedFilterData[1].filterType === "Attachments") {
console.log(JSON.stringify(advancedFilterData[1].data));
}
this.onCreateAdvancedFilterObject(advancedFilterFn);
}
I have an array of object, I want to add key in my specifi object of array when Id is matched. I have tried this:
this.data.forEach(value => {
if (value.Id === attachmentDataId) {
AttachmentTypeId: this.attachmentRecord.AttachmentType;
}
});
But it's not working and it's not giving any error also
Try this out :
let data = [{ id: 1 }, { id: 5 }];
const attachmentDataId = 5;
const attachmentRecord = { AttachmentType: "AttachmentType" };
data.forEach(value => {
if (value.id === attachmentDataId) {
value.AttachmentTypeId = attachmentRecord.AttachmentType;
}
});
The stackblitz example: https://stackblitz.com/edit/js-nrhouh
You could use the index parameter of forEach function to access the specific object of the array.
this.data.forEach((value, i) => {
if (value.Id === attachmentDataId) {
this.data[i] = {
...this.data[i],
AttachmentTypeId: this.attachmentRecord.AttachmentType
};
}
});
Inside the if block, you could also instead do
this.data[i]['AttachmentTypeId'] = this.attachmentRecord.AttachmentType;
I just find using the spread operator cleaner.
use javascript map() method.
Map() return a new array, it takes a callback, iterates on each element in that array
const updatedData = data.map(res => {
if(res.id === attachmentDataId) {
res.AttachmentTypeId = attachmentRecord.AttachmentType;
}
return res
})
I want to make filter by date with this object of array
const mapDateRange = () => {for (let elem in catchData) {
let x = {startDate:catchData[elem][0],finishDate:catchData[elem][1]};
return x;
}};
but its only catch one object of array
this is latest data has processing
const data = {
["01-08-2019", "08-08-2019"],
["08-08-2019", "15-08-2019"],
["15-08-2019", "22-08-2019"],
["22-08-2019", "29-08-2019"]
};
this is what i expected
const data = [
{
startDate:"01-08-2019", finisDate:"08-08-2019"
},
{
startDate:"08-08-2019", finisDate:"15-08-2019"
},
{
startDate:"15-08-2019", finisDate:"22-08-2019"
},
{
startDate:"22-08-2019", finisDate:"29-08-2019"
}
];
So there are a few problems in the code you wrote:
Your data started as an object ({}), but its built as an array, so I corrected that.
Your function mapDateRange uses catchData but it does not exist anywhere so I made the function except an argument, which will be the catchData.
Most important: You returned x which is only 1 item in the array of data. So I created an empty array and pushed x values to the array.
const data = [
["01-08-2019", "08-08-2019"],
["08-08-2019", "15-08-2019"],
["15-08-2019", "22-08-2019"],
["22-08-2019", "29-08-2019"]
];
const mapDateRange = (catchData) => {
let new_data = [];
for (let elem in catchData) {
let x = {
startDate: catchData[elem][0],
finishDate: catchData[elem][1]
};
new_data.push(x);
}
return new_data;
};
console.log(mapDateRange(data));
const data = [
["01-08-2019", "08-08-2019"],
["08-08-2019", "15-08-2019"],
["15-08-2019", "22-08-2019"],
["22-08-2019", "29-08-2019"]
];
const mapDataRange = (data) => {
const result = [];
data.forEach((item) => {
const x = { 'startDate': item[0], 'finishDate': item[1] };
result.push(x);
});
return result;
}
console.log(mapDatatRange(data));
In this way you will get your desire result by using map function
data = data.map((obj) => {
return {
startDate: obj[0],
finishDate: obj[1]
}
});
console.log(data)
try to do with .map and array destructuring with ES6 syntax
data.map(([ startDate, finishDate ]) => { startDate, finisDate })
A React component is passed a state property, which is an object of objects:
{
things: {
1: {
name: 'fridge',
attributes: []
},
2: {
name: 'ashtray',
attributes: []
}
}
}
It is also passed (as a router parameter) a name. I want the component to find the matching object in the things object by comparing name values.
To do this I use the filter method:
Object.keys(this.props.things).filter((id) => {
if (this.props.things[id].name === this.props.match.params.name) console.log('found!');
return (this.props.things[id].name === this.props.match.params.name);
});
However this returns undefined. I know the condition works because of my test line (the console.log line), which logs found to the console. Why does the filter method return undefined?
Object.keys returns an array of keys (like maybe ["2"] in your case).
If you are interested in retrieving the matching object, then you really need Object.values. And if you are expecting one result, and not an array of them, then use find instead of filter:
Object.values(this.props.things).find((obj) => {
if (obj.name === this.props.match.params.name) console.log('found!');
return (obj.name === this.props.match.params.name);
});
Be sure to return that result if you use it within a function. Here is a snippet based on the fiddle you provided in comments:
var state = {
things: {
1: {
name: 'fridge',
attributes: []
},
2: {
name: 'ashtray',
attributes: []
}
}
};
var findThing = function(name) {
return Object.values(state.things).find((obj) => {
if (obj.name === name) console.log('found!');
return obj.name === name;
});
}
var result = findThing('fridge');
console.log(result);
You need to assign the result of filter to a object and you get the result as the [id]. You then need to get the object as this.props.things[id]
var data = {
things: {
1: {
name: 'fridge',
attributes: []
},
2: {
name: 'ashtray',
attributes: []
}
}
}
var name = 'fridge';
var newD = Object.keys(data.things).filter((id) => {
if (data.things[id].name === name) console.log('found!');
return (data.things[id].name === name);
});
console.log(data.things[newD]);
I want to be able to pass any javascript object containing camelCase keys through a method and return an object with underscore_case keys, mapped to the same values.
So, I have this:
var camelCased = {firstName: 'Jon', lastName: 'Smith'}
And I want a method to output this:
{first_name: 'Jon', last_name: 'Jon'}
What's the fastest way to write a method that takes any object with any number of key/value pairs and outputs the underscore_cased version of that object?
Here's your function to convert camelCase to underscored text (see the jsfiddle):
function camelToUnderscore(key) {
return key.replace( /([A-Z])/g, "_$1").toLowerCase();
}
console.log(camelToUnderscore('helloWorldWhatsUp'));
Then you can just loop (see the other jsfiddle):
var original = {
whatsUp: 'you',
myName: 'is Bob'
},
newObject = {};
function camelToUnderscore(key) {
return key.replace( /([A-Z])/g, "_$1" ).toLowerCase();
}
for(var camel in original) {
newObject[camelToUnderscore(camel)] = original[camel];
}
console.log(newObject);
If you have an object with children objects, you can use recursion and change all properties:
function camelCaseKeysToUnderscore(obj){
if (typeof(obj) != "object") return obj;
for(var oldName in obj){
// Camel to underscore
newName = oldName.replace(/([A-Z])/g, function($1){return "_"+$1.toLowerCase();});
// Only process if names are different
if (newName != oldName) {
// Check for the old property name to avoid a ReferenceError in strict mode.
if (obj.hasOwnProperty(oldName)) {
obj[newName] = obj[oldName];
delete obj[oldName];
}
}
// Recursion
if (typeof(obj[newName]) == "object") {
obj[newName] = camelCaseKeysToUnderscore(obj[newName]);
}
}
return obj;
}
So, with an object like this:
var obj = {
userId: 20,
userName: "John",
subItem: {
paramOne: "test",
paramTwo: false
}
}
newobj = camelCaseKeysToUnderscore(obj);
You'll get:
{
user_id: 20,
user_name: "John",
sub_item: {
param_one: "test",
param_two: false
}
}
es6 node solution below. to use, require this file, then pass object you want converted into the function and it will return the camelcased / snakecased copy of the object.
const snakecase = require('lodash.snakecase');
const traverseObj = (obj) => {
const traverseArr = (arr) => {
arr.forEach((v) => {
if (v) {
if (v.constructor === Object) {
traverseObj(v);
} else if (v.constructor === Array) {
traverseArr(v);
}
}
});
};
Object.keys(obj).forEach((k) => {
if (obj[k]) {
if (obj[k].constructor === Object) {
traverseObj(obj[k]);
} else if (obj[k].constructor === Array) {
traverseArr(obj[k]);
}
}
const sck = snakecase(k);
if (sck !== k) {
obj[sck] = obj[k];
delete obj[k];
}
});
};
module.exports = (o) => {
if (!o || o.constructor !== Object) return o;
const obj = Object.assign({}, o);
traverseObj(obj);
return obj;
};
Came across this exact problem when working between JS & python/ruby objects. I noticed the accepted solution is using for in which will throw eslint error messages at you ref: https://github.com/airbnb/javascript/issues/851 which alludes to rule 11.1 re: use of pure functions rather than side effects ref:https://github.com/airbnb/javascript#iterators--nope
To that end, figured i'd share the below which passed the said rules.
import { snakeCase } from 'lodash'; // or use the regex in the accepted answer
camelCase = obj => {
const camelCaseObj = {};
for (const key of Object.keys(obj)){
if (Object.prototype.hasOwnProperty.call(obj, key)) {
camelCaseObj[snakeCase(key)] = obj[key];
}
}
return camelCaseObj;
};
Marcos Dimitrio posted above with his conversion function, which works but is not a pure function as it changes the original object passed in, which may be an undesireable side effect. Below returns a new object that doesn't modify the original.
export function camelCaseKeysToSnake(obj){
if (typeof(obj) != "object") return obj;
let newObj = {...obj}
for(var oldName in newObj){
// Camel to underscore
let newName = oldName.replace(/([A-Z])/g, function($1){return "_"+$1.toLowerCase();});
// Only process if names are different
if (newName != oldName) {
// Check for the old property name to avoid a ReferenceError in strict mode.
if (newObj.hasOwnProperty(oldName)) {
newObj[newName] = newObj[oldName];
delete newObj[oldName];
}
}
// Recursion
if (typeof(newObj[newName]) == "object") {
newObj[newName] = camelCaseKeysToSnake(newObj[newName]);
}
}
return newObj;
}
this library does exactly that: case-converter
It converts snake_case to camelCase and vice versa
const caseConverter = require('case-converter')
const snakeCase = {
an_object: {
nested_string: 'nested content',
nested_array: [{ an_object: 'something' }]
},
an_array: [
{ zero_index: 0 },
{ one_index: 1 }
]
}
const camelCase = caseConverter.toCamelCase(snakeCase);
console.log(camelCase)
/*
{
anObject: {
nestedString: 'nested content',
nestedArray: [{ anObject: 'something' }]
},
anArray: [
{ zeroIndex: 0 },
{ oneIndex: 1 }
]
}
*/
following what's suggested above, case-converter library is deprectaed, use snakecase-keys instead -
https://github.com/bendrucker/snakecase-keys
supports also nested objects & exclusions.
Any of the above snakeCase functions can be used in a reduce function as well:
const snakeCase = [lodash / case-converter / homebrew]
const snakeCasedObject = Object.keys(obj).reduce((result, key) => ({
...result,
[snakeCase(key)]: obj[key],
}), {})
jsfiddle
//This function will rename one property to another in place
Object.prototype.renameProperty = function (oldName, newName) {
// Do nothing if the names are the same
if (oldName == newName) {
return this;
}
// Check for the old property name to avoid a ReferenceError in strict mode.
if (this.hasOwnProperty(oldName)) {
this[newName] = this[oldName];
delete this[oldName];
}
return this;
};
//rename this to something like camelCase to snakeCase
function doStuff(object) {
for (var property in object) {
if (object.hasOwnProperty(property)) {
var r = property.replace(/([A-Z])/, function(v) { return '_' + v.toLowerCase(); });
console.log(object);
object.renameProperty(property, r);
console.log(object);
}
}
}
//example object
var camelCased = {firstName: 'Jon', lastName: 'Smith'};
doStuff(camelCased);
Note: remember to remove any and all console.logs as they aren't needed for production code