remove Empty Properties from Array - javascript

Can someone help here:
Working good with objects
But code is breaking in empty Arrays
const removeEmptyProperties = (obj) => {
obj = Array.isArray(obj) ? obj.filter(val => val !== 'null' || val !== 'undefined') : obj;
Object.keys(obj).forEach((key) => {
//recursive for nested objects
if (obj[key] && typeof obj[key] === 'object')
removeEmptyProperties(obj[key]);
//remove empty properties
else if (
typeof obj[key] !== 'boolean' &&
(obj[key] == null || obj[key] == '')
)
delete obj[key];
//remove empty objects
if (
typeof obj[key] !== 'boolean' &&
typeof obj[key] === 'object' &&
Object.keys(obj[key]).length == 0
)
delete obj[key];
});
};
let data = {
questionDetails: [
{
trees: 123,
template: {
id : null
}
},
{
trees: 123,
},
],
};
delete data.questionDetails[1];
removeEmptyProperties(data);
console.log(data); => { questionDetails: [ { trees: 123 }, <1 empty item> ] }
But expected result should be { questionDetails: [ { trees: 123 } ] }, My code is breaking in empty array

You could take an approach where the function returns a boolean for the calling scope for deleting a property or element.
Check if value is falsy or not an object.
Return true if value is an unwanted value, of false for every other value.
Check if value is an array.
Iterate the array from the end, because Array#slice changes the index of elements with greater index. Smaller indices are not affected.
Call the function removeEmptyProperties with the element and splice if the element has to be removed.
Return true for an empty array.
At last you got an object.
Take the keys and iterate them.
Call the function removeEmptyProperties with the value and delete the property, if true.
Return true for an object with no own properties.
At the end, all empty array/objects and uunwanted properties are removed.
const
removeEmptyProperties = value => {
if (!value || typeof value !== 'object') {
return [undefined, null, ''].includes(value);
}
if (Array.isArray(value)) {
let i = value.length;
while (i--) if (removeEmptyProperties(value[i])) value.splice(i, 1);
return !value.length;
}
Object.keys(value).forEach(k => {
if (removeEmptyProperties(value[k])) delete value[k];
});
return !Object.keys(value).length;
};
let data = { questionDetails: [{}, { id: null, foo: 0, bar: undefined }] };
removeEmptyProperties(data);
console.log(data);
data.questionDetails[0].foo = '';
removeEmptyProperties(data);
console.log(data);

Related

parsed javascript object in array by remove null values [duplicate]

How do I remove all attributes which are undefined or null in a JavaScript object?
(Question is similar to this one for Arrays)
ES10/ES2019 examples
A simple one-liner (returning a new object).
let o = Object.fromEntries(Object.entries(obj).filter(([_, v]) => v != null));
Same as above but written as a function.
function removeEmpty(obj) {
return Object.fromEntries(Object.entries(obj).filter(([_, v]) => v != null));
}
This function uses recursion to remove items from nested objects.
function removeEmpty(obj) {
return Object.fromEntries(
Object.entries(obj)
.filter(([_, v]) => v != null)
.map(([k, v]) => [k, v === Object(v) ? removeEmpty(v) : v])
);
}
ES6/ES2015 examples
A simple one-liner. Warning: This mutates the given object instead of returning a new one.
Object.keys(obj).forEach((k) => obj[k] == null && delete obj[k]);
A single declaration (not mutating the given object).
let o = Object.keys(obj)
.filter((k) => obj[k] != null)
.reduce((a, k) => ({ ...a, [k]: obj[k] }), {});
Same as above but written as a function.
function removeEmpty(obj) {
return Object.entries(obj)
.filter(([_, v]) => v != null)
.reduce((acc, [k, v]) => ({ ...acc, [k]: v }), {});
}
This function uses recursion to remove items from nested objects.
function removeEmpty(obj) {
return Object.entries(obj)
.filter(([_, v]) => v != null)
.reduce(
(acc, [k, v]) => ({ ...acc, [k]: v === Object(v) ? removeEmpty(v) : v }),
{}
);
}
Same as the function above, but written in an imperative (non-functional) style.
function removeEmpty(obj) {
const newObj = {};
Object.entries(obj).forEach(([k, v]) => {
if (v === Object(v)) {
newObj[k] = removeEmpty(v);
} else if (v != null) {
newObj[k] = obj[k];
}
});
return newObj;
}
ES5/ES2009 examples
In the old days things were a lot more verbose.
This is a non recursive version written in a functional style.
function removeEmpty(obj) {
return Object.keys(obj)
.filter(function (k) {
return obj[k] != null;
})
.reduce(function (acc, k) {
acc[k] = obj[k];
return acc;
}, {});
}
This is a non recursive version written in an imperative style.
function removeEmpty(obj) {
const newObj = {};
Object.keys(obj).forEach(function (k) {
if (obj[k] && typeof obj[k] === "object") {
newObj[k] = removeEmpty(obj[k]);
} else if (obj[k] != null) {
newObj[k] = obj[k];
}
});
return newObj;
}
And a recursive version written in a functional style.
function removeEmpty(obj) {
return Object.keys(obj)
.filter(function (k) {
return obj[k] != null;
})
.reduce(function (acc, k) {
acc[k] = typeof obj[k] === "object" ? removeEmpty(obj[k]) : obj[k];
return acc;
}, {});
}
You can loop through the object:
var test = {
test1: null,
test2: 'somestring',
test3: 3,
}
function clean(obj) {
for (var propName in obj) {
if (obj[propName] === null || obj[propName] === undefined) {
delete obj[propName];
}
}
return obj
}
console.log(test);
console.log(clean(test));
If you're concerned about this property removal not running up object's proptype chain, you can also:
function clean(obj) {
var propNames = Object.getOwnPropertyNames(obj);
for (var i = 0; i < propNames.length; i++) {
var propName = propNames[i];
if (obj[propName] === null || obj[propName] === undefined) {
delete obj[propName];
}
}
}
A few notes on null vs undefined:
test.test1 === null; // true
test.test1 == null; // true
test.notaprop === null; // false
test.notaprop == null; // true
test.notaprop === undefined; // true
test.notaprop == undefined; // true
Shortest one liners for ES6+
Filter all falsy values ( "", 0, false, null, undefined )
Object.entries(obj).reduce((a,[k,v]) => (v ? (a[k]=v, a) : a), {})
Filter null and undefined values:
Object.entries(obj).reduce((a,[k,v]) => (v == null ? a : (a[k]=v, a)), {})
Filter ONLY null
Object.entries(obj).reduce((a,[k,v]) => (v === null ? a : (a[k]=v, a)), {})
Filter ONLY undefined
Object.entries(obj).reduce((a,[k,v]) => (v === undefined ? a : (a[k]=v, a)), {})
Recursive Solutions: Filters null and undefined
For Objects:
const cleanEmpty = obj => Object.entries(obj)
.map(([k,v])=>[k,v && typeof v === "object" ? cleanEmpty(v) : v])
.reduce((a,[k,v]) => (v == null ? a : (a[k]=v, a)), {});
For Objects and Arrays:
const cleanEmpty = obj => {
if (Array.isArray(obj)) {
return obj
.map(v => (v && typeof v === 'object') ? cleanEmpty(v) : v)
.filter(v => !(v == null));
} else {
return Object.entries(obj)
.map(([k, v]) => [k, v && typeof v === 'object' ? cleanEmpty(v) : v])
.reduce((a, [k, v]) => (v == null ? a : (a[k]=v, a)), {});
}
}
If you are using lodash or underscore.js, here is a simple solution:
var obj = {name: 'John', age: null};
var compacted = _.pickBy(obj);
This will only work with lodash 4, pre lodash 4 or underscore.js, use _.pick(obj, _.identity);
If somebody needs a recursive version of Owen's (and Eric's) answer, here it is:
/**
* Delete all null (or undefined) properties from an object.
* Set 'recurse' to true if you also want to delete properties in nested objects.
*/
function delete_null_properties(test, recurse) {
for (var i in test) {
if (test[i] === null) {
delete test[i];
} else if (recurse && typeof test[i] === 'object') {
delete_null_properties(test[i], recurse);
}
}
}
JSON.stringify removes the undefined keys.
removeUndefined = function(json){
return JSON.parse(JSON.stringify(json))
}
You can use a combination of JSON.stringify, its replacer parameter, and JSON.parse to turn it back into an object. Using this method also means the replacement is done to all nested keys within nested objects.
Example Object
var exampleObject = {
string: 'value',
emptyString: '',
integer: 0,
nullValue: null,
array: [1, 2, 3],
object: {
string: 'value',
emptyString: '',
integer: 0,
nullValue: null,
array: [1, 2, 3]
},
arrayOfObjects: [
{
string: 'value',
emptyString: '',
integer: 0,
nullValue: null,
array: [1, 2, 3]
},
{
string: 'value',
emptyString: '',
integer: 0,
nullValue: null,
array: [1, 2, 3]
}
]
};
Replacer Function
function replaceUndefinedOrNull(key, value) {
if (value === null || value === undefined) {
return undefined;
}
return value;
}
Clean the Object
exampleObject = JSON.stringify(exampleObject, replaceUndefinedOrNull);
exampleObject = JSON.parse(exampleObject);
CodePen example
Simplest possible Lodash solution to return an object with the null and undefined values filtered out.
_.omitBy(obj, _.isNil)
You can do a recursive removal in one line using json.stringify's replacer argument
const removeEmptyValues = obj => (
JSON.parse(JSON.stringify(obj, (k,v) => v ?? undefined))
)
Usage:
removeEmptyValues({a:{x:1,y:null,z:undefined}}) // Returns {a:{x:1}}
As mentioned in Emmanuel's comment, this technique only worked if your data structure contains only data types that can be put into JSON format (strings, numbers, lists, etc).
(This answer has been updated to use the new Nullish Coalescing operator. depending on browser support needs you may want to use this function instead: (k,v) => v!=null ? v : undefined)
You are probably looking for the delete keyword.
var obj = { };
obj.theProperty = 1;
delete obj.theProperty;
you can do shorter with ! condition
var r = {a: null, b: undefined, c:1};
for(var k in r)
if(!r[k]) delete r[k];
Remember in usage : as #semicolor announce in comments: This would also delete properties if the value is an empty string, false or zero
Remove all the properties with null and undefined
let obj = {
"id": 1,
"firstName": null,
"lastName": null,
"address": undefined,
"role": "customer",
"photo": "fb79fd5d-06c9-4097-8fdc-6cebf73fab26/fc8efe82-2af4-4c81-bde7-8d2f9dd7994a.jpg",
"location": null,
"idNumber": null,
};
let result = Object.entries(obj).reduce((a,[k,v]) => (v == null ? a : (a[k]=v, a)), {});
console.log(result)
I have same scenario in my project and achieved using following method.
It works with all data types, few mentioned above doesn't work with date and empty arrays .
removeEmptyKeysFromObject.js
removeEmptyKeysFromObject(obj) {
Object.keys(obj).forEach(key => {
if (Object.prototype.toString.call(obj[key]) === '[object Date]' && (obj[key].toString().length === 0 || obj[key].toString() === 'Invalid Date')) {
delete obj[key];
} else if (obj[key] && typeof obj[key] === 'object') {
this.removeEmptyKeysFromObject(obj[key]);
} else if (obj[key] == null || obj[key] === '') {
delete obj[key];
}
if (obj[key]
&& typeof obj[key] === 'object'
&& Object.keys(obj[key]).length === 0
&& Object.prototype.toString.call(obj[key]) !== '[object Date]') {
delete obj[key];
}
});
return obj;
}
pass any object to this function removeEmptyKeysFromObject()
Using ramda#pickBy you will remove all null, undefined and false values:
const obj = {a:1, b: undefined, c: null, d: 1}
R.pickBy(R.identity, obj)
As #manroe pointed out, to keep false values use isNil():
const obj = {a:1, b: undefined, c: null, d: 1, e: false}
R.pickBy(v => !R.isNil(v), obj)
Shorter ES6 pure solution, convert it to an array, use the filter function and convert it back to an object.
Would also be easy to make a function...
Btw. with this .length > 0 i check if there is an empty string / array, so it will remove empty keys.
const MY_OBJECT = { f: 'te', a: [] }
Object.keys(MY_OBJECT)
.filter(f => !!MY_OBJECT[f] && MY_OBJECT[f].length > 0)
.reduce((r, i) => { r[i] = MY_OBJECT[i]; return r; }, {});
JS BIN https://jsbin.com/kugoyinora/edit?js,console
Functional and immutable approach, without .filter and without creating more objects than needed
Object.keys(obj).reduce((acc, key) => (obj[key] === undefined ? acc : {...acc, [key]: obj[key]}), {})
Instead of delete the property, you can also create a new object with the keys that are not null.
const removeEmpty = (obj) => {
return Object.keys(obj).filter(key => obj[key]).reduce(
(newObj, key) => {
newObj[key] = obj[key]
return newObj
}, {}
)
}
For a deep search I used the following code, maybe it will be useful for anyone looking at this question (it is not usable for cyclic dependencies ) :
function removeEmptyValues(obj) {
for (var propName in obj) {
if (!obj[propName] || obj[propName].length === 0) {
delete obj[propName];
} else if (typeof obj[propName] === 'object') {
removeEmptyValues(obj[propName]);
}
}
return obj;
}
Here is a comprehensive recursive function (originally based on the one by #chickens) that will:
recursively remove what you tell it to defaults=[undefined, null, '', NaN]
Correctly handle regular objects, arrays and Date objects
const cleanEmpty = function(obj, defaults = [undefined, null, NaN, '']) {
if (!defaults.length) return obj
if (defaults.includes(obj)) return
if (Array.isArray(obj))
return obj
.map(v => v && typeof v === 'object' ? cleanEmpty(v, defaults) : v)
.filter(v => !defaults.includes(v))
return Object.entries(obj).length
? Object.entries(obj)
.map(([k, v]) => ([k, v && typeof v === 'object' ? cleanEmpty(v, defaults) : v]))
.reduce((a, [k, v]) => (defaults.includes(v) ? a : { ...a, [k]: v}), {})
: obj
}
USAGE:
// based off the recursive cleanEmpty function by #chickens.
// This one can also handle Date objects correctly
// and has a defaults list for values you want stripped.
const cleanEmpty = function(obj, defaults = [undefined, null, NaN, '']) {
if (!defaults.length) return obj
if (defaults.includes(obj)) return
if (Array.isArray(obj))
return obj
.map(v => v && typeof v === 'object' ? cleanEmpty(v, defaults) : v)
.filter(v => !defaults.includes(v))
return Object.entries(obj).length
? Object.entries(obj)
.map(([k, v]) => ([k, v && typeof v === 'object' ? cleanEmpty(v, defaults) : v]))
.reduce((a, [k, v]) => (defaults.includes(v) ? a : { ...a, [k]: v}), {})
: obj
}
// testing
console.log('testing: undefined \n', cleanEmpty(undefined))
console.log('testing: null \n',cleanEmpty(null))
console.log('testing: NaN \n',cleanEmpty(NaN))
console.log('testing: empty string \n',cleanEmpty(''))
console.log('testing: empty array \n',cleanEmpty([]))
console.log('testing: date object \n',cleanEmpty(new Date(1589339052 * 1000)))
console.log('testing: nested empty arr \n',cleanEmpty({ 1: { 2 :null, 3: [] }}))
console.log('testing: comprehensive obj \n', cleanEmpty({
a: 5,
b: 0,
c: undefined,
d: {
e: null,
f: [{
a: undefined,
b: new Date(),
c: ''
}]
},
g: NaN,
h: null
}))
console.log('testing: different defaults \n', cleanEmpty({
a: 5,
b: 0,
c: undefined,
d: {
e: null,
f: [{
a: undefined,
b: '',
c: new Date()
}]
},
g: [0, 1, 2, 3, 4],
h: '',
}, [undefined, null]))
Here's an alternative
Typescript:
function objectDefined <T>(obj: T): T {
const acc: Partial<T> = {};
for (const key in obj) {
if (obj[key] !== undefined) acc[key] = obj[key];
}
return acc as T;
}
Javascript:
function objectDefined(obj) {
const acc = {};
for (const key in obj) {
if (obj[key] !== undefined) acc[key] = obj[key];
}
return acc;
}
If you want 4 lines of a pure ES7 solution:
const clean = e => e instanceof Object ? Object.entries(e).reduce((o, [k, v]) => {
if (typeof v === 'boolean' || v) o[k] = clean(v);
return o;
}, e instanceof Array ? [] : {}) : e;
Or if you prefer more readable version:
function filterEmpty(obj, [key, val]) {
if (typeof val === 'boolean' || val) {
obj[key] = clean(val)
};
return obj;
}
function clean(entry) {
if (entry instanceof Object) {
const type = entry instanceof Array ? [] : {};
const entries = Object.entries(entry);
return entries.reduce(filterEmpty, type);
}
return entry;
}
This will preserve boolean values and it will clean arrays too. It also preserves the original object by returning a cleaned copy.
a reduce helper can do the trick (without type checking) -
const cleanObj = Object.entries(objToClean).reduce((acc, [key, value]) => {
if (value) {
acc[key] = value;
}
return acc;
}, {});
If you don't want to mutate in place, but return a clone with the null/undefined removed, you could use the ES6 reduce function.
// Helper to remove undefined or null properties from an object
function removeEmpty(obj) {
// Protect against null/undefined object passed in
return Object.keys(obj || {}).reduce((x, k) => {
// Check for null or undefined
if (obj[k] != null) {
x[k] = obj[k];
}
return x;
}, {});
}
To piggypack on Ben's answer on how to solve this problem using lodash's _.pickBy, you can also solve this problem in the sister library: Underscore.js's _.pick.
var obj = {name: 'John', age: null};
var compacted = _.pick(obj, function(value) {
return value !== null && value !== undefined;
});
See: JSFiddle Example
You can also use ... spread syntax using forEach something like this:
let obj = { a: 1, b: "b", c: undefined, d: null };
let cleanObj = {};
Object.keys(obj).forEach(val => {
const newVal = obj[val];
cleanObj = newVal ? { ...cleanObj, [val]: newVal } : cleanObj;
});
console.info(cleanObj);
If someone needs to remove undefined values from an object with deep search using lodash then here is the code that I'm using. It's quite simple to modify it to remove all empty values (null/undefined).
function omitUndefinedDeep(obj) {
return _.reduce(obj, function(result, value, key) {
if (_.isObject(value)) {
result[key] = omitUndefinedDeep(value);
}
else if (!_.isUndefined(value)) {
result[key] = value;
}
return result;
}, {});
}
With Lodash:
_.omitBy({a: 1, b: null}, (v) => !v)
If you use eslint and want to avoid tripping the the no-param-reassign rule, you can use Object.assign in conjunction with .reduce and a computed property name for a fairly elegant ES6 solution:
const queryParams = { a: 'a', b: 'b', c: 'c', d: undefined, e: null, f: '', g: 0 };
const cleanParams = Object.keys(queryParams)
.filter(key => queryParams[key] != null)
.reduce((acc, key) => Object.assign(acc, { [key]: queryParams[key] }), {});
// { a: 'a', b: 'b', c: 'c', f: '', g: 0 }
Here is a functional way to remove nulls from an Object using ES6 without mutating the object using only reduce:
const stripNulls = (obj) => {
return Object.keys(obj).reduce((acc, current) => {
if (obj[current] !== null) {
return { ...acc, [current]: obj[current] }
}
return acc
}, {})
}
Recursively remove null, undefined, empty objects and empty arrays, returning a copy (ES6 version)
export function skipEmpties(dirty) {
let item;
if (Array.isArray(dirty)) {
item = dirty.map(x => skipEmpties(x)).filter(value => value !== undefined);
return item.length ? item : undefined;
} else if (dirty && typeof dirty === 'object') {
item = {};
Object.keys(dirty).forEach(key => {
const value = skipEmpties(dirty[key]);
if (value !== undefined) {
item[key] = value;
}
});
return Object.keys(item).length ? item : undefined;
} else {
return dirty === null ? undefined : dirty;
}
}

How to find the key of a nested object by the value in javascript?

I have a nested object as follows, and I want to find out the key name if value is given to me.
const a = {
"key1": 12,
"key2": {
"nkey1": 123,
"nkey2": 345
}
};
const temp = (obj, val) => {
return Object.keys(obj).find(key => !(typeof obj[key] === "object") ? obj[key] === val : temp(obj[key], val))
}
console.log(temp(a, 345));
I wrote the above piece of code. But it gives me output as key2 whereas I want output as nkey2.
What am I doing wrong?
A function returns null if the value is not found, otherwise return the key.
const findKey = (obj, val) => {
if (typeof obj === "object") {
for (const key in obj) {
if (obj[key] === val) {
return key;
} else {
const result = findKey(obj[key], val);
if (result !== null) return result;
}
}
}
return null;
};
const a = {
key1: 12,
key2: {
nkey1: 123,
nkey2: 345,
nkey3: {
dkey1: 232,
dkey2: 777,
},
},
};
const output = findKey(a, 777);
console.log(output);
You can use for-in loop, to iterate over keys. If the value of that key matches val, you can return the key. Else, you can check if value is an object, and use recursion, to check if val matches any value of key in that object.
const a = {
"key1": 12,
"key2": {
"nkey1": 123,
"nkey2": 345
}
};
const temp = (obj, val) => {
for (let i in obj) {
if(obj[i] === val){
return i;
} else if(typeof obj[i] === "object"){
return temp(obj[i], val);
}
}
}
console.log(temp(a, 345));
Take a look at this:
const a = {
"key1": 12,
"key2": {
"nkey1": 123,
"nkey2": 345
}
};
// recursive loop
const find = (obj, search = null) => {
if (typeof obj === "object") {
for (const key in obj) { // loop over each property
if (obj.hasOwnProperty(key) && obj[key] === search) // if obj[key] is the value you are looking for (search)
return key; // return key
else {
let r = find(obj[key], search); // recursive call to find with the new object
if (r !== null) return r; // return key
}
}
}
return null; // default return value is null
}
console.log(12, find(a, 12));
console.log(123, find(a, 123));
console.log(345, find(a, 345));
console.log(0, find(a, 0));
The find() function returns the first value of the the array for which the condition is true.
In the case of key === "key2" the recursive function is called which returns "nkey2" which results in the condition to be true and thats why "key2" is returned.
So again maybe to clear my way of thinking: You expect the find() function to return the result of a function call which is part of a condition. This wont work.
The condition is true on key2 so find returns key2.
Hope this helps you out!

Recursively list nested object keys

i have an nested object as such:
options = {
religous: {
kosher: {
value: 'Kosher',
chosen: false
},
halal: {
value: 'Halal',
active: false
},
},
vegan: {
value: 'Vegan',
active: false
}
}
It contains nested objects of varying sizes. I would like to get an Array containing the values of any value propery. So for the above object the desired output would be:
['Kosher', 'Halal', 'Vegan']
Order doesn't really matter.
I tried to do so recursively as such:
getListOfLabels = obj => {
const lst = []
for (let key in obj) {
if (obj[key].value) lst.push(obj[key].value)
else return getListOfLabels(obj[key])
}
return lst
}
but I keep getting a RangeError: Maximum call stack size exceeded error.
Any suggestions?
The for...in loop assigns the key. To get the value use obj[key]. If the key is value add to lst, if it's an object, call getListOfLabels on it, and spread the results into lst.push():
const options = {"religous":{"kosher":{"value":"Kosher","chosen":false},"halal":{"value":"Halal","active":false}},"vegan":{"value":"Vegan","active":false}}
const getListOfLabels = obj => {
const lst = []
for (let key in obj) {
const val = obj[key] // get the value
if (key === 'value') lst.push(val) // if the key name is "value" push to lst
else if(typeof val === 'object') lst.push(...getListOfLabels(val)) // if type of value is object, iterate it with getListOfLabels and push the results into lst
}
return lst
}
const result = getListOfLabels(options)
console.log(result)
You could take a recursive approach and check if the object contains a value key.
function getValues(object, key) {
if (key in object) return [object[key]];
return Object.values(object).reduce((r, v) => {
if (v && typeof v === 'object') r.push(...getValues(v, key));
return r;
}, []);
}
var options = { religous: { kosher: { value: 'Kosher', chosen: false }, halal: { value: 'Halal', active: false } }, vegan: { value: 'Vegan', active: false } };
console.log(getValues(options, 'value'));
Here's a succinct approach using reduce :-D
const getValues = options => Object.values(options)
.reduce((acc, optionObj) => (
optionObj.value ? [ ...acc, optionObj.value ] : [
...acc,
...Object.values(optionObj).reduce((arr, { value }) => ([ ...arr, value ]), [])
]), [])

Delete null or undefined attributes in object

I want to create a method to delete null and undefined attributes.
To do that :
I convert my plain object into table
loop on it
filter on attributes if there are null or undefined
But the thing is I don't arrive to restructure my object with the new values. Let's take a look :
var req = {
adtForm1: {
firstName: 'John',
lastName: undefined,
middleName: ''
},
adtForm2: {
firstName: null,
lastName: 'Doe',
middleName: ''
}
};
removeUndefinedFormsAttributes = (somesForms) => {
const forms = Object.values(somesForms);
const formsUpdate = {};
forms.forEach(item => {
const formFields = Object.values(item);
formFieldsKeys = Object.keys(item);
const formFiltered = formFields.filter(field => { return field !== null && field !== undefined; });
console.log("formFiltered", formFiltered);
})
console.log(somesForms)
return forms;
};
removeUndefinedFormsAttributes(req)
As we can see in the snippet, formFiltered change the good values but I need to return the same object as somesForms.
This is what I need :
expectedValue = {
adtForm1: {
firstName: 'John',
middleName: ''
},
adtForm2: {
lastName: 'Doe',
middleName: ''
}
}
I know I need to use reduce() function and keys() function but truly I don't know how. I will really appreciate any help.
If you just need to remove keys with null or undefined values from objects nested one level down, then you can iterate over the values of your main object using Object.values, then iterate over the keys of each nested object using Object.keys, and delete those that match your conditions. You can test the values of your nested objects to determine if they are null or undefined with something like value == null (see How to determine if variable is undefined or null?).
If you need to remove keys at various nested levels in your object or in an object where some of the nested values are of different types, then check out some of the other answers that employ recursion and type checking.
For example:
const req = { adtForm1: { firstName: 'John', lastName: undefined, middleName: '' }, adtForm2: { firstName: null, lastName: 'Doe', middleName: '' } };
Object.values(req).forEach((v) => {
Object.keys(v).forEach((k) => {
if (v[k] == null) {
delete v[k];
}
});
});
console.log(req);
// {"adtForm1":{"firstName":"John","middleName":""},"adtForm2":{"lastName":"Doe","middleName":""}}
You can recursively iterate the object and create a new object without null or undefined. Use Object.entries() to get the keys and value pairs from the object. Iterate the pairs with Array.reduce. Ff a value is null or undefined skip it's key. If it's an object assign the result of calling removeUndefinedFormsAttributes on the value to the key. And if it's not an object just assign the value to the key.
const req = {"adtForm1":{"firstName":"John","middleName":""},"adtForm2":{"firstName":null,"lastName":"Doe","middleName":""}};
const removeUndefinedFormsAttributes = (obj) =>
Object.entries(obj).reduce((r, [k, v]) => {
if(v === null || v === undefined) return r;
if(typeof v === 'object') r[k] = removeUndefinedFormsAttributes(v);
else r[k] = v;
return r;
}, {});
const result = removeUndefinedFormsAttributes(req)
console.log(result)
If I understand, you need to modify the actual object instead of creating a new structure. If so, then you don't want .reduce(). You just need a recursive function that modifies the given object.
var req = {
adtForm1: {
firstName: 'John',
lastName: undefined,
middleName: ''
},
adtForm2: {
firstName: null,
lastName: 'Doe',
middleName: ''
}
};
function removeUndefinedFormsAttributes(obj) {
Object.entries(obj)
.forEach(([k, v]) => {
if (v == null) {
delete obj[k];
} else if (typeof v === "object") {
removeUndefinedFormsAttributes(v);
}
})
};
removeUndefinedFormsAttributes(req);
console.log(req);
Here I used Object.entries to get the key/value pairs for the given object.
If v is null or undefined, it will delete that k from the object. If v is an object, it makes a recursive call with that object.
FYI, doing v == null is the same as doing v === null || v === undefined
Try this one
let removeNotNeedet = ( obj ) => {
let newObj = {}
for (const key in obj) {
if ( obj[key] !== null && obj[key] !== undefined ){
newObj[key] = obj[key]
}
}
return newObj
}
You can simply clone those attributes into a new object if their aren't null or undefined.
Quite simple code that loops recursively through obj and only insert attributes if they are valid:
function clearObject(object) {
if (typeof(object) != "object") return false;
const clean_object = {};
for (let k in object) {
let item = object[k];
if (item === null || item === undefined) continue;
clean_object[k] = clearObject(item) || item;
}
return clean_object;
}

finding undefined or null value from object inside object

i would like to push keys inside array if found undefined or null
const obj = {
name:'ab',
edu:'av',
degres:{
a1:'',
b1:'1'
},
platform:undefined
}
i want an output like
`['a1','platform']`
as the value for a1 and platform were null and undefined
i have treid this solution but it doesnt work
function iterater(obj){
let blankValues = [];
Object.keys(obj).map((key) => {
if (obj.hasOwnProperty(key) && (typeof obj[key] === "object")) {
iterater(obj[key])
} else {
if (typeof obj[key] === "undefined" || obj[key] === ''){
blankValues.push(key);
}
}
})
return blankValues;
}
but this somehow only return ['platform'] only,but the expected output should be ['platform','a1'],i think when running iterater(obj[key]),the value of array (blankValues) gets blank as it doesnt perserve it,but please help me with appropriate logic and structure
The issue is because you're re-defining blankValues as an empty array in every iteration of the recursive loop. To fix this you could accept the array as an optional argument of the function so that values get pushed to it on each iteration.
Also note that, as #ziggy wiggy pointed out in the comments, your logic will fail when a null value is encountered as typeof obj[key] === "object" would be true. You need a specific null check too.
const obj = {
name: 'ab',
edu: 'av',
degres: {
a1: '',
b1: '1'
},
platform: undefined,
foo: null
}
function iterater(obj, arr) {
arr = arr || [];
Object.keys(obj).map((key) => {
if (obj.hasOwnProperty(key) && (typeof obj[key] === "object") && obj[key] !== null) {
iterater(obj[key], arr)
} else {
if (typeof obj[key] === "undefined" || obj[key] === null || obj[key].trim() === '') {
arr.push(key);
}
}
})
return arr;
}
console.log(iterater(obj));
Note that I also added a trim() call to test the empty string. Your previous logic would accept whitespace-filled strings as valid values.
As you said yourself, when you call iterater(obj[key]) it sets a new local blankValues and puts values in it. So i think you should put blankValues outside the function.
And then you don't have to return it (or you can if you want it as a return value).
Or you can pass blankValues as a parameter of iterater in both the main call and the "inside" call
You need to consume the result of recursive call. For example add it back to blankValues like this blankValues.push(...iterater(obj[key]))
const obj = {
name:'ab',
edu:'av',
degres:{
a1:'',
b1:'1'
},
platform:undefined
}
function iterater(obj){
let blankValues = [];
Object.keys(obj).map((key) => {
if (obj.hasOwnProperty(key) && (typeof obj[key] === "object")) {
blankValues.push(...iterater(obj[key]))
} else {
if (typeof obj[key] === "undefined" || obj[key] === ''){
blankValues.push(key);
}
}
})
return blankValues;
}
console.log(iterater(obj))
You must push the result returned by the recursive call to your array.
Change:
iterater(obj[key])
for:
blankValues.push(...iterater(obj[key]))
const obj = {
name: 'ab',
edu: 'av',
degres: {
a1: '',
b1: '1'
},
platform: undefined
}
function iterater(obj){
let blankValues = [];
Object.keys(obj).map((key) => {
if (obj.hasOwnProperty(key) && (typeof obj[key] === "object")) {
blankValues.push(...iterater(obj[key]))
} else {
if (typeof obj[key] === "undefined" || obj[key] === ''){
blankValues.push(key);
}
}
})
return blankValues;
}
console.log(iterater(obj));
Here is another way to do it using Object.entries(), Object.keys(), Array.reduce(), Array.flat() and Array.isArray(). This implementation works for arrays too.
const obj = {
name:'ab',
edu:'av',
something: [{ a: 1 }, { a: '' }],
degres:{
a1:'',
b1:'1'
},
platform:undefined
};
function getEmptyProps(obj) {
if (!Object.keys(obj).length) { return []; }
return Object.entries(obj).reduce((acc, [key, val]) => {
if (val === undefined || val === null || val.toString().trim() === '') {
acc.push(key);
} else if (Array.isArray(val)) {
acc.push(val.map(getEmptyProps).flat());
} else if (typeof val === 'object') {
acc.push(getEmptyProps(val));
}
return acc.flat();
}, []);
}
console.log(getEmptyProps(obj))
You could take a check for falsy keys and return the key, if the property is an object, the check the object.
const
getFalsy = o => Object.keys(o).reduce((r, k) => {
if (!o[k]) return [...r, k];
if (typeof o[k] === 'object') return [...r, ...getFalsy(o[k])];
return r;
}, []),
object = { name: 'ab', edu: 'av', degres: { a1: '', b1: '1' }, platform: undefined };
console.log(getFalsy(object));

Categories