I've run into questions similar to this one, but they generally pertain on how to remove an underscore whereas I am having the issue of removing the underscore in a for loop. When console logging in my function it will show that the fields I want changed do in fact change but when I return the object it only returns an object where all keys have snake case. I think this may be a scope issue but after playing around with the different placement of variables I keep getting stuck. Below is an example of the original object I would like to change:
const originalObj = {
accountNumber: '12345',
company: [
{
address: {
line1: '123',
line2: 'Spring Street'
}
}
],
ownerInfo: [
{
firstName: 'John',
lastName: 'Doe'
enrollment: '2015-10-15'
}
],
tax: {
code: '12345'
}
}
Using the npm package change-case-object I am able to successfully change all keys with camel case to snake case. However, I do not want any key that has a numeric value to include an underscore (like with the cases of line1 and line2). With this function
import changeCaseObject from 'change-case-object';
export function restructure(originalObj) {
const regex = /\d/g;
let newObj;
if(typeof originalObj === "object"){
newObj = changeCaseObject.snakeCase(originalObj);
for(const key in newObj){
if(typeof newObj[key] === "object" && newObj[key] !== null){
restructure(newObj[key])
//if the value is an object use recursion
} else {
if(regex.test(key)){
let newKey = key.replace(/_/g, '');
newObj.newKey = newObj.key;
delete newObj.key;
}
}
}
}
return newObj;
}
When I add a console log in the case where the key matches the regex, it will show that "line_1" does in fact change to "line1" along with "line_2". However when returning newObj it just returns the object in which all values now have snake case (as shown below)
{
account_number: '12345',
company: [
{
address: {
line_1: '123',
line_2: 'Spring Street'
}
}
],
owner_info: [
{
first_name: 'John',
last_name: 'Doe'
enrollment: '2015-10-15'
}
],
tax: {
code: '12345'
}
}
I feel like there is something very simple that I am overlooking but defining newObj outside of the if else statement has not led to success either. Thank you for your time.
Related
The function I declared takes an object and an array of keys to ensure that the object has the correct keys. I also want to validate the values if they are not empty and check their types as well.
isObjectEmpty(obj) is a function that checks if object is not empty
While it works for keys, I am not sure how to check the types of values and their data
const localStorageDataValidation = (obj, whiteList) => {
if (!isObjectEmpty(obj)) {
const newObj = Object.fromEntries(
Object.entries(obj).filter(([key, value]) => {
return whiteList.includes(key);
}),
);
return newObj;
}
}
my object looks like this:
const obj = {
user: {
name:"",
email: "",
lastName: "",
},
userOrders: [{id: "1", count: 2, price: 2, title: ""}];
adress: {street: "", location: ""};
delivery: 1;
}
You can add another filter after the first one to validate the values. You can use typeof to check the type and check if the value is not an empty string or undefined.
I have a type coming from a 3rd party API which has a lot of properties (50+) and they take all values as string. The even number and booleans became strings ("5" and "false" respectively) and I want to fix the scary thing.
So I created a type like this to receive the response from API and to hold after fix
interface Person {
age: string | number,
name: string,
hasChildren: string | boolean,
...
}
And I want to transform this
const responseFromApi: Person = {
age: "20",
name: "John",
numberOfChildren: "true"
...
}
to
const afterTreatment: Person = {
age: 21,
name: "John",
numberOfChildren: true
...
}
This is an example... My object, again, is much bigger than this, with a lot of props in this situation so treat them individually is not the kind of solution I'm looking for.
My intention is to iterate over the object and change to number or boolean what can be changed following type.
You could for-loop the array, check if the element.age is a string and if yes parseInt the age and set it again.
A better solution would maybe be to map though the list, and do the same thing as above, just so it creates a new array, which you could then overwrite/do what you need.
Idea:
const changed = persons.map((p: Person) => {
if (typeof p.age === "string") {
return {
...p,
age:parseInt(p.age)
}
}
return p
});
This should work as long as the variable conventions are consistent with person1, person2, person3 etc and also you need to know the total number of added persons for the forloop to work
interface Person {
age: string | number,
name: string
}
const person1: Person = {
age: 20,
name: "Jonh",
}
const person2: Person = {
age: "21",
name: "Marie",
}
const lengthOfPersons: number = 2;
const newArray = [];
for(let i = 0; i < lengthOfPersons; i++)
{
const n = i + 1;
const row = eval('person'+n);
newArray.push({...row, age: +row.age})
}
console.log(newArray);
Let's say I have some code, like this:
const filter = {
address: 'India',
name: 'Aleena'
};
const users = [{
name: 'John Doe',
email: 'johndoe#mail.com',
age: 25,
address: 'USA'
},
{
name: 'Aleena',
email: 'aleena#mail.com',
age: 35,
address: 'India'
},
{
name: 'Mark Smith',
email: 'marksmith#mail.com',
age: 28,
address: 'England'
}
];
const filteredUsers = users.filter((item) => {
for (var key in filter) {
if (item[key] === undefined || item[key] != filter[key])
return false;
}
return true;
});
How can I dynamically update/change the filter object to allow users to choose which key:values to use in the filtering process? I know people normally use React for this kind of stuff, but I wondered if there was a "vanilla" way to do it.
Actually, filter does it for you already. Filter returns a new filtered array without mutating the original array.
"Users" is the original array. "FilteredUsers" is the newly created filtered array off users.
To clone/copy the original Users array above, you can do:
let clonedArray = [...Users]
The users array is a perfect candidate for this. Let's say you want to add all of the users ages together. It's pretty cool-simple.
1- function addAges(acc,ele) {return acc + ele.age}
2- Users.reduce(addAges, 0);
That'it. No console.log either. It'll returned the sum
here's a very basic example in CodeSandBox to get an idea of what to do.
I believe it meets the requirements of your question
https://codesandbox.io/s/vanila-js-dynamic-filter-6yhhe6?file=/src/index.js
I'm trying to destructure and ignore few values, how do I do that?
For example:
const test = { name: 'John', age: 29, gender: 'male'}
function getData(...args) {
const {,,gender} = args[0];
console.log(gender); // should print male.
}
getData(test);
I want to ignore (not declare variables for) name and age parameters (so that my ESLint does not throw an error) at the same time use ES6.
The syntax , does not seem to work either. Any other workarounds for this problem?
You have a single arg (the object), and you should object destructuring to get gender:
const test = { name: 'John', age: 29, gender: 'male'}
function getData(arg) {
const { gender} = arg;
console.log(gender); // should print male.
}
getData(test);
I have 2 sources of data. One of the sources is the "template" to what is acceptable for the data. However, the second source may have a large amount of data that I don't care about (100+ properties in the JSON). Here are the schemas:
// Only store the data we care about. Only a small subset of
// data that I need for this particular dataset.
state = {
isDirty: false,
data: {
name: '',
address: '',
city: '',
state: ''
}
}
The second source will have the 4 attributes in the data schema above (plus many many more I don't care about). Currently, I am assigning them like this:
let updatedData = {};
for(const key in this.state.data) {
updatedData[key] = someDataSource[key];
}
this.state.data = updatedData;
Using ES6, and perhaps destructing, is there a better way to mass assign variables like this?
Thanks again!
EDIT
Added for clarification the assignment after the loop.
Lodash pick can be used to pick specific keys, or helper function can be used for same purpose:
const pick = (obj, keys) => Object.keys(obj)
.filter((key) => keys.indexOf(key) >= 0)
.reduce(
(newObj, key) => Object.assign(newObj, { [key]: obj[key] }),
{}
);
This is already suggested in many related questions. The thing that is specific to this question is:
this.state.data = pick(someDataSource, Object.keys(this.state.data));
Properties can be excluded and modified in the JSON.parse reviver :
var o = JSON.parse('{"a":1, "b":2}', (k, v) => k === 'a' ? void 0 : k === 'b' ? 3 : v)
console.log( o )
A trick you can do (trick because it requires to swallow an error) is to use an non extensible object, using the Object.preventExtensions and then use Object.assign to fill it with data (in a try/catch block).
// Only store the data we care about. Only a small subset of
// data that I need for this particular dataset.
state = {
isDirty: false,
data: {
name: '',
address: '',
city: '',
state: ''
}
}
const newData = {
name:'name',
address:'address',
city:'city',
state:'state',
phone:'phone',
zip:'zip'
}
const updatedData = Object.preventExtensions({...state.data});
try{
Object.assign(updatedData, newData);
} catch(throwaway){};
console.log(updatedData);
And as a function for reuse
function schemaMerge(schema, data) {
const mergedData = Object.preventExtensions({...schema});
try {
Object.assign(mergedData, data);
} catch (throwaway) {};
return ({...mergedData}); // create a new object from the merged one so that it no longer is extensionless
}
// Only store the data we care about. Only a small subset of
// data that I need for this particular dataset.
state = {
isDirty: false,
data: {
name: '',
address: '',
city: '',
state: ''
}
}
const newData = {
name: 'name',
address: 'address',
city: 'city',
state: 'state',
phone: 'phone',
zip: 'zip'
}
const updatedData = schemaMerge(state.data, newData);
state.data = updatedData;
console.log(state.data);