Why this gives me the properties:
const person = {
id: 1,
firstName: 'Jack',
lastName: 'White',
age: 25,
};
const json = JSON.stringify(person, (key, value) => typeof(value) == "string" ? undefined : value);
console.log(json);
But this gives me 'undefined':
const person = {
id: 1,
firstName: 'Jack',
lastName: 'White',
age: 25,
};
const json = JSON.stringify(person, (key, value) => typeof(value) == "number" ? value : undefined);
console.log(json);
Can't get the differences. Is there a syntax error or just can't works in this way?
Because the entire object is evaluated first, and then each key/value pair. You are denying the object first, because it is not a number, so the whole thing is undefined. If you match objects and numbers, it works.
const person = {
id: 1,
firstName: 'Jack',
lastName: 'White',
age: 25,
};
const json = JSON.stringify(person, (key, value) => (typeof(value) == "number" || typeof(value) == "object") ? value : undefined);
console.log(json);
This means:
typeof(value) == "string" ? undefined : value
When a string is found, return undefined. Otherwise, return the original value. So, strings get removed.
This means:
typeof(value) == "number" ? value : undefined
When a number is found, return that number. Otherwise, return undefined. So, non-numbers get removed. The only value that would produce a result would be a plain number.
const json = JSON.stringify(3, (key, value) => typeof(value) == "number" ? value : undefined);
console.log(json);
Perhaps you meant to do
typeof value == "number" ? undefined : value
removing numbers, but keeping everything else as is.
const person = {
id: 1,
firstName: 'Jack',
lastName: 'White',
age: 25,
};
const json = JSON.stringify(person, (key, value) => typeof(value) == "number" ? undefined : value);
console.log(json);
Or perhaps you meant to remove only non-number primitives.
typeof value === "object" || typeof value === 'number' ? value : undefined
const person = {
id: 1,
firstName: 'Jack',
lastName: 'White',
age: 25,
};
const json = JSON.stringify(person, (key, value) => typeof value === "object" || typeof value === 'number' ? value : undefined);
console.log(json);
Related
I have ask another question, but someone close that question. I really need this answer. That's why I asking another question.
I have a object like following. I have to remove that empty string filed from nested object and also from nested array. How can I remove that.
const obj = {
name: 'Red Boy',
price: '350',
originalPrice: '', // Empty string field
stock: 20,
category: {
name: '', // Empty String field
subCategory: { name: ''} // Empty String filed
},
weight: '90kg',
dimensions: {
width: '50cm',
height: '', // Empty string filed
length: '70cm'
},
suitable: [
{ name: 'Yoga' },
{ name: '' }, // Empty String filed
{ name: 'Winter' }
],
additionalInfo: [
{ field: 'closure', value: 'Button' },
{ field: 'collar', value: ''} // Empty String Field
]
}
In this hybrid object type you can see some sub-object and also some sub-array. You can also see some field that are not contain any value.(I comment out that filed).
Actually I need to remove that filed. How can I remove that empty string field from above hybrid object type.
Thank you..
My Expected result-
{
name: 'Red Boy',
price: '350',
// Removed
stock: 20,
category: {
name: '', // Empty String field
// Removed
},
weight: '90kg',
dimensions: {
width: '50cm',
// Removed
length: '70cm'
},
suitable: [
{ name: 'Yoga' },
//Removed
{ name: 'Winter' }
],
additionalInfo: [
{ field: 'closure', value: 'Button' },
{ field: 'collar', //Removed }
// Here If this two filed is empty then should remove the whole object
{ field: '', value: '' }
// Then should remove whole '{ field: '', value: '' }'
]
}
To achieve this, we need to implement a recursive function to remove all empty string in all nested arrays and objects.
function rec(obj){
for(let key of Object.keys(obj)){
if (obj[key] === ''){
delete obj[key];
}
else if (typeof obj[key] === 'object'){
obj[key] = rec(obj[key]);
if (Object.keys(obj[key]).length === 0 ) delete obj[key];
}
}
return Array.isArray(obj) ? obj.filter(val => val) : obj;
}
Also, please note that it's not purely hybrid. Because Array is special type of Object.
const obj = {
name: 'Red Boy',
price: '350',
originalPrice: '', // Empty string field
stock: 20,
category: {
name: '', // Empty String field
subCategory: { name: ''} // Empty String filed
},
weight: '90kg',
dimensions: {
width: '50cm',
height: '', // Empty string filed
length: '70cm'
},
suitable: [
{ name: 'Yoga' },
{ name: '' }, // Empty String filed
{ name: 'Winter' }
],
additionalInfo: [
{ field: 'closure', value: 'Button' },
{ field: 'collar', value: ''} // Empty String Field
]
}
function removeEmptyString(object) {
Object
.entries(object)
.forEach(([key, value]) => {
if (value && typeof value === 'object')
removeEmptyString(value);
if (value &&
typeof value === 'object' &&
!Object.keys(value).length ||
value === null ||
value === undefined ||
value.length === 0
) {
if (Array.isArray(object))
object.splice(key, 1);
else
delete object[key];
}
});
return object;
}
console.log(removeEmptyString(obj))
I have used recursion to filter out the empty string, empty object or empty array present deep inside the nested structure.
This function also removes such objects and their nested objects with no properties.
Note: It will also work if the provided initial value is any other thing then object like array or string
var obj={name:"Red Boy",price:"350",originalPrice:"",stock:20,category:{name:"",subCategory:{name:""}},weight:"90kg",dimensions:{width:"50cm",height:"",length:"70cm"},suitable:[{name:"Yoga"},{name:""},{name:"Winter"}],additionalInfo:[{field:"closure",value:"Button"},{field:"collar",value:""}]};
function filt(a) {
if (typeof a === 'string') return a !== '';
//if it is a string, then it must not be empty
else if (Array.isArray(a)) return a.length !== 0
//if it an arra, then it must have some item
else if (a instanceof Object) return Object.keys(a).length !== 0;
//if it is an object, then it must have some property
return a !== null && a !== undefined
//else it must not be null or undefined
}
function rec(obj) {
if (Array.isArray(obj)) {
//if an value is an array
return obj.map((a) => rec(a)).filter((a) => filt(a)) //recurse the child first of each value in the array
//then filter out the value which are either null, empty, undefined or have length 0
} else if (obj instanceof Object) {
//if value is an object
var d = Object.entries(obj).map((a) => ([a[0], rec(a[1])])).filter((a) => filt(a[1]));
//map through the object.entries and reassign the values to the keys by recurssing over the value to filter out the nested inside irrelevant value
return Object.fromEntries(d)
//convert the map into object and return
} else if (typeof obj === 'string') return obj !== '' ? obj : null
//f it is a string, it must not be empty else return null
return obj !== null && obj !== undefined ? obj : null
//else it must not be null or undefined
}
console.log("For object",rec(obj))
console.log("For Array",rec([{
name: "Yoga"
}, {
name: ""
}, {
name: "Winter"
}]))
Here's an immutable way to remove non-empty values from an object, with the added capability of normalising object's inside of arrays:
const normaliseObject = (obj) =>
Object.fromEntries(
Object.entries(obj)
.filter(([_, value]) => value !== '' && value !== null)
.map(([key, value]) => (typeof value === 'object' ? [key, normalise(value)] : [key, value])),
)
// If an element in an array is an object, normalise that too
const normaliseArray = (arr) => arr.map(value => (typeof value === 'object' ? normalise(value) : value))
/**
* Normalise any object to remove keys whose values are falsey
* #param obj Object to be normalised
* #returns Normalised object where falsey values are removed
*/
const normalise = (obj) => {
return Array.isArray(obj) ? normaliseArray(obj) : normaliseObject(obj)
}
I have a model that looks as follows
this.Model
Model {class: undefined items: Array(0) tag: undefined launch: undefined length: undefined name: undefined Id: "de4d704a-b754-4546-b3ab-f0c131eba84a" time: "15:36" tonnage: undefined}
the only objects in the Model that will always have a value is Id and Time.
i have an if statement that goes through each off my objects to check if its null as follows:
if ( this.Model.class == null && this.Model.name == null && this.Model.tag== null && this.Model.launch == null && this.Model.length == null && this.Model.tonnage == null && this.Model.items.length == 0)
{
//does something in here
}
so i want to check if all the objects are null except time and ID, is there a better way of doing this than me using the above method in an if statement?
I would create a function to check about that using Object.entries and Array.every.
Perks of this solution :
Reusable utility function.
Works with any number of keys to ignore.
The typing of the function will throw an error in case you specify a key to ignore that is not a part of the provided object.
Playground in TypeScript
Snippet in Javascript.
function checkAllKeysExceptGivenKeysToBeNullable(obj, keys) {
return Object.entries(obj).every(([
key,
value,
]) => {
// If the key has to be ignored
if (keys.includes(key)) {
return true;
}
// Check the value to be nullable
return value === null ||
value === void 0 ||
(value instanceof Array && value.length === 0);
});
}
console.log(checkAllKeysExceptGivenKeysToBeNullable({
class: undefined,
items: Array(0),
tag: undefined,
launch: undefined,
length: undefined,
name: undefined,
Id: 'de4d704a-b754-4546-b3ab-f0c131eba84a',
time: '15:36',
tonnage: undefined,
}, [
'Id',
'time',
]));
console.log(checkAllKeysExceptGivenKeysToBeNullable({
class: undefined,
items: Array(0),
tag: 'nope',
launch: undefined,
length: undefined,
name: undefined,
Id: 'de4d704a-b754-4546-b3ab-f0c131eba84a',
time: '15:36',
tonnage: undefined,
}, [
'Id',
'time',
]));
function checkAllKeysExceptGivenKeysToBeNullable<T extends {
[key in keyof T]: null | undefined | Array<unknown> | unknown;
}>(obj: T, keys: (keyof T)[]): boolean {
return Object.entries(obj).every(([
key,
value,
]) => {
if (keys.includes(key as keyof T)) {
return true;
}
return value === null ||
value === void 0 ||
(value instanceof Array && value.length === 0);
});
}
console.log(checkAllKeysExceptGivenKeysToBeNullable({
class: undefined,
items: Array(0),
tag: undefined,
launch: undefined,
length: undefined,
name: undefined,
Id: 'de4d704a-b754-4546-b3ab-f0c131eba84a',
time: '15:36',
tonnage: undefined,
}, [
'Id',
'time',
]));
console.log(checkAllKeysExceptGivenKeysToBeNullable({
class: undefined,
items: Array(0),
tag: 'nope',
launch: undefined,
length: undefined,
name: undefined,
Id: 'de4d704a-b754-4546-b3ab-f0c131eba84a',
time: '15:36',
tonnage: undefined,
}, [
'Id',
'time',
]));
After playing around a bit, I came up with a solution using Object.keys()
/**
* Checks if all of the objects values are null, except for keys in param except
* #param obj: The object to test
* #param except (optional): keys to omit the null check on
*/
function checkIfPropertiesNull(obj: {[key: string]: unknown}, except: string[] = []): boolean {
const keys = Object.keys(obj).filter(key => !except.includes(key));
for(const key of keys){
if(obj[key] !== null){
return false;
}
}
return true;
}
console.log(checkIfPropertiesNull({ id: 1, name: 'mike', city: null }, ['id', 'name'])); // true, because id and name are not checked
console.log(checkIfPropertiesNull({ id: 1, name: 'mike', city: 'Munich' }, ['id', 'name'])); // false, city isn't null
Playground
for (let prop in Modal) {
if (Modal.prop != time && Modal.prop != id && Modal[prop] != null) {
return false
}
}
return true
Return true if all properties except ID and Time are null.
Well, you have two options in this case:
Put your loop in a function to separate this logic to your model:
function checkProperties(obj) {
for (var key in obj) {
if (obj[key] !== null && obj[key] != "")
return false;
}
return true;
}
var obj = {
x: null,
y: "",
z: 1
}
checkProperties(obj) //returns false
Use Object.values and every to check your properties as an array.
let report = {
property1: null,
property2: null,
}
let result = !Object.values(report).every(o => o === null);
console.log(result);
I have in my app some filters. Whenever I click search, the data should be filtered based on the values of the search. I don't know if there's a better way to do what I'm trying to do in a cooler way or fancy way. The values of the search are being stored the following way:
FORM_VALUES =
{
title: '',
name: 'John',
Age: 56
}
If the value of the objects are empty '' then I shouldn't considered them when i filter the array of objects.
My array of Objects looks like this:
[
{
title:'CEO',
name: 'John',
Age: 56
},
{
title: null,
name: 'George',
Age: 56
},
]
In this example, it should return the first element of the array.
My code:
data.filter(d => {
if ((d.title === FORM_VALUES.title || FORM_VALUES.title === '')
&& (d.name === FORM_VALUES.name || FORM_VALUES.name === '')
&& (d.age === FORM_VALUES.age || FORM_VALUES.age === '')) {
return d;
}
});
Use filter to get the people with the values, and use Object.keys and delete to remove any empty entries, and every with Object.entries to find the actual objects:
const FORM_VALUES = {
title: '',
name: 'John',
Age: 56
}
const data = [{
title: 'CEO',
name: 'John',
Age: 56
},
{
title: null,
name: 'George',
Age: 56
}
];
let searchObj = { ...FORM_VALUES };
Object.keys(searchObj).forEach(key => searchObj[key] == "" ? delete searchObj[key] : key);
const found = data.filter(d => Object.entries(searchObj).every(([k, v]) => d[k] == v));
console.log(found);
Get an array of key/value pairs from the FORM_VALUES object with Object.entries(). Iterate the array of pairs with Array.every() for each pair, return true if the value '' (empty string) or value of the filter matches with that of the current object.
const FORM_VALUES = {"title":"","name":"John","Age":56}
const data = [{"title":"CEO","name":"John","Age":56},{"title":null,"name":"George","Age":56}]
const result = data.filter(o =>
Object.entries(FORM_VALUES)
.every(([k, v]) => v === '' || o[k] === v)
)
console.log(result)
I have a simple function that updates the values of an object. Currently, the function takes in 3 parameters to updated the object. I would like an optional fourth parameter that will accept an array of objects (array) and change the values for all the objects in the array. If the fourth parameter is provided I would like to ignore the others. What is the best way to do this? Thanks
var myObj = {myKey : 0}
var obj1 = {myKey : 0}
var obj2 = {myKey : 0}
var array = [{obj: obj1, key: 'myKey1', value: 1},{obj: obj2, key: 'myKey2', value: 2}]
function changeRule(obj, key, value) {
obj[key] = value
},
changeRule(myObj, 'myKey', 1)
Check if 4th parameter is undefined and if it is an array
var myObj = {
myKey: 0
}
var obj1 = {
myKey: 0
}
var obj2 = {
myKey: 0
}
var array = [{
obj: obj1,
key: 'myKey1',
value: 1
}, {
obj: obj2,
key: 'myKey2',
value: 2
}]
function changeRule(obj, key, value, array) {
if (array! == undefined && Array.isArray(array)) {
// rest of the code to change the object properties
return;
}
obj[key] = value
},
changeRule(myObj, 'myKey', 1, array)
Check if it works for your problem statement, copy code and run in developer console, it won't run here properly.
var obj1 = {
myKey: 0
};
var obj2 = {
myKey: 0
};
var array = [{
obj: 'obj1',
key: 'myKey',
value: 1
}, {
obj: 'obj2',
key: 'myKey',
value: 2
}]
function changeRule(objOrArray, key, value) {
if (objOrArray !== undefined && Array.isArray(objOrArray)) {
//code that would change value of all objects according to data in array
objOrArray.forEach(_obj => {
eval(_obj.obj)[_obj.key] = _obj.value;
});
return;
} else if (objOrArray !== undefined && key !== undefined && value !== undefined) {
objOrArray[key] = value;
} else {
console.warn('param1 must be an Array, or Object with param2(key) & param3(value)');
}
return;
}
changeRule(array);
console.log(obj1, obj2);
Note: I have made a change in the structure of array of objects. (obj name is should be a string.)
This is what I went with. Thanks for all the help! I learned a lot from this post.
var myObj = {
myKey: 0
}
var obj1 = {
myKey1: 0
}
var obj2 = {
myKey2: 0
}
var array = [{
obj: obj1,
key: 'myKey1',
value: 1
}, {
obj: obj2,
key: 'myKey2',
value: 2
}]
function changeRule() {
if (arguments.length == 1 && Array.isArray(arguments[0])) {
arguments[0].forEach(e => {
e.obj[e.key] = e.value
});
} else if (arguments.length == 3 && typeof arguments[0] == "object" && typeof arguments[1] == "string" && typeof arguments[2] == "number") {
arguments[0][arguments[1]] = arguments[2]
} else {
return "Unacceptable input parameters"
}
}
console.log(obj1)
console.log("------------------------")
changeRule(array);
console.log(obj1)
I have the following object and a value -
{
location:"xyz",
title:"abc",
company: {
address:"address can have spaces",
name:"name"
},
array-key :[
{ skill : "skill1"},
{ skill : "skill2"},
{ skill : "skill3"}
],
description :"brief description"
}
and now I have a value - "spaces", now I want to check if "spaces" is present in the object at any level. If "spaces" is present function should return true.
I tried the recursive way but how should I handle the array?
One useful trick for iterating recursively over an object is to use the replacer parameter to JSON.stringify.
function findString(obj, regexp) {
let found = false;
JSON.stringify(obj, (k, v) => {
if (found || typeof v === 'string' && regexp.test(v)) found = true;
else return v;
});
return found;
}
Just for completeness with iterating all levels recursively and checking the value either strict or as string and with String#indexOf.
function check(object, value) {
return Object.keys(object).some(function (key) {
if (object[key] && typeof object[key] === 'object') {
return check(object[key], value);
}
return object[key] === value || object[key].toString().indexOf(value) + 1;
});
}
var data = { location: "xyz", title: "abc", company: { address: "address can have spaces", name: "name" }, arrayKey: [{ skill: "skill1" }, { skill: "skill2" }, { skill: "skill3" }], description: "brief description" };
console.log(check(data, "spaces"));
console.log(check(data, "foo"));