Javascript filter null object properties - javascript

I have an Array with one or more objects and I want to filter out all null properties:
asset = [{"ObjId":177791,"ObjCreditlineM":"DEU","ObjReprorechtM":null,"ObjKommentarM":null,"ObjZustandM":null,"ObjReserve01M":null,"ObjReserve02M":null,"ObjFeld01M":null,"ObjFeld02M":null,"ObjFeld03M":null,"ObjFeld04M":"Foto","ObjFeld05M":null,"ObjFeld06M":null,"ObjFeld07M":null,"ObjFeld01S":null,"ObjFeld02S":null,"ObjFeld03S":null,"ObjFeld04S":null,"ObjFeld05S":null,"ObjFeld06S":null,"ObjFeld07S":null,"ObjFeld01F":0,"ObjFeld02F":0,"ObjFeld01D":null,"ObjFeld02D":null,"ObjInv01S":null,"ObjInv02S":null,"ObjInv03S":null,"ObjInv04S":null,"ObjInv05S":null,"ObjInv06S":null,"ObjDinId":0,"ObjReferenz01Id":null,"ObjReferenz02Id":null,"ObjTransferId":null,"ObjGesperrtS":null,"ObjIconTextM":null}]
// My attempt:
var filledProps = asset.map(el => {
if (Object.keys(el)) { // check if object property value is not null
return el;
};
});
console.log(filledProps);
But I get the same object properties back. What am I missing?

It sounds like you want to create a new array with new objects that only have the properties that aren't null from the original. Is so, map is where you want to start, but Object.keys(el) is always truthy, since it returns an array of property names. You're close though:
var asset = [{"ObjId":177791,"ObjCreditlineM":"DEU","ObjReprorechtM":null,"ObjKommentarM":null,"ObjZustandM":null,"ObjReserve01M":null,"ObjReserve02M":null,"ObjFeld01M":null,"ObjFeld02M":null,"ObjFeld03M":null,"ObjFeld04M":"Foto","ObjFeld05M":null,"ObjFeld06M":null,"ObjFeld07M":null,"ObjFeld01S":null,"ObjFeld02S":null,"ObjFeld03S":null,"ObjFeld04S":null,"ObjFeld05S":null,"ObjFeld06S":null,"ObjFeld07S":null,"ObjFeld01F":0,"ObjFeld02F":0,"ObjFeld01D":null,"ObjFeld02D":null,"ObjInv01S":null,"ObjInv02S":null,"ObjInv03S":null,"ObjInv04S":null,"ObjInv05S":null,"ObjInv06S":null,"ObjDinId":0,"ObjReferenz01Id":null,"ObjReferenz02Id":null,"ObjTransferId":null,"ObjGesperrtS":null,"ObjIconTextM":null}]
// Use `map` to get a new array with new objects
var filledProps = asset.map(el => {
// Loop the property names of `el`, creating a new object
// with the ones whose values aren't `null`.
// `reduce` is commonly used for doing this:
return Object.keys(el).reduce((newObj, key) => {
const value = el[key];
if (value !== null) {
newObj[key] = value;
}
return newObj;
}, {});
});
console.log(filledProps);
What am I missing?
Since if (Object.keys(el)) is always truthy, your code was just always returning el unchanged. It wasn't creating a new object, or deleting properties with null values from the original object.
The above creates new objects, but if you like, you can just delete properties from the originals that have null values instead:
var asset = [{"ObjId":177791,"ObjCreditlineM":"DEU","ObjReprorechtM":null,"ObjKommentarM":null,"ObjZustandM":null,"ObjReserve01M":null,"ObjReserve02M":null,"ObjFeld01M":null,"ObjFeld02M":null,"ObjFeld03M":null,"ObjFeld04M":"Foto","ObjFeld05M":null,"ObjFeld06M":null,"ObjFeld07M":null,"ObjFeld01S":null,"ObjFeld02S":null,"ObjFeld03S":null,"ObjFeld04S":null,"ObjFeld05S":null,"ObjFeld06S":null,"ObjFeld07S":null,"ObjFeld01F":0,"ObjFeld02F":0,"ObjFeld01D":null,"ObjFeld02D":null,"ObjInv01S":null,"ObjInv02S":null,"ObjInv03S":null,"ObjInv04S":null,"ObjInv05S":null,"ObjInv06S":null,"ObjDinId":0,"ObjReferenz01Id":null,"ObjReferenz02Id":null,"ObjTransferId":null,"ObjGesperrtS":null,"ObjIconTextM":null}];
asset.forEach(el => {
Object.keys(el).forEach(key => {
if (el[key] === null) {
delete el[key];
}
});
});
console.log(asset);
Two aspects of that to call out, though:
It modifies the original objects (and thus, in a way, the original array).
When you delete a property from an object, it can have an impact on the performance of property lookup on that object afterward. 99.999% of the time you don't care, but it's there.

asset = [{"ObjId":177791,"ObjCreditlineM":"DEU","ObjReprorechtM":null,"ObjKommentarM":null,"ObjZustandM":null,"ObjReserve01M":null,"ObjReserve02M":null,"ObjFeld01M":null,"ObjFeld02M":null,"ObjFeld03M":null,"ObjFeld04M":"Foto","ObjFeld05M":null,"ObjFeld06M":null,"ObjFeld07M":null,"ObjFeld01S":null,"ObjFeld02S":null,"ObjFeld03S":null,"ObjFeld04S":null,"ObjFeld05S":null,"ObjFeld06S":null,"ObjFeld07S":null,"ObjFeld01F":0,"ObjFeld02F":0,"ObjFeld01D":null,"ObjFeld02D":null,"ObjInv01S":null,"ObjInv02S":null,"ObjInv03S":null,"ObjInv04S":null,"ObjInv05S":null,"ObjInv06S":null,"ObjDinId":0,"ObjReferenz01Id":null,"ObjReferenz02Id":null,"ObjTransferId":null,"ObjGesperrtS":null,"ObjIconTextM":null}]
var filledProps = asset.map(el => {
var obj = {};
for(var prop in el) {
if(el[prop] !== null) {
obj[prop] = el[prop];
}
}
return obj;
});
console.log(filledProps);

Related

Create JSON object accoring to request.body

Using NodeJs + Express to create a REST API. Everything works well, but I can't understand how to iterate through the request.body and check its fields for undefined and empty values and assign new object only with valid data.
request.body looks like:
{
key: 'value',
otherKey: 'otherValue',
oneMoreKey: '',
oneMoreKey2: undefined,
oneMoreKey3: null
}
At that end my object shoud look like:
let contactData = Object.assign({},{
'key': 'value',
'otherKey': 'otherValue'
})
Looking for your advices and help
JavaScript
function getCleanObject(oldObject) {
var newObject = {};
for (var property in oldObject) {
var value = oldObject[property];
if (value) newObject[property] = value;
}
}
Explanation
You can start off by creating a new clean Object
var newObject = {}; // same as new Object();
Then iterate through all of the object's properties using a for loop.
for (var property in oldObject)
Then get the value of that property
var value = oldObject[property];
If the value is Troothy add the property to the new Object
if (value) newObject[property] = value;
Note that this way the false value will be rejected. To allow it to be copied to the new Object you should replace the if statement with
if(value || value === false)
Moreover, if the Object you are copying also inherits from some other Object it is possible that it will have extra properties as well and if you do not want them to be included you should change the if statement to
if(value && oldObject.hasOwnProperty(value))
And Remember for(var item in object) != for(var item of list)
in is used to iterate through an object's properties whereas of is used to iterate through an iteratable (i.e. list). Also in is supported in all browsers whereas of is not supported by internet explorer.
your_object = {
key: request.body[key] || 'default',
otherKey: request.body[otherKey] || 'default',
oneMoreKey: request.body[oneMoreKey] || 'default'
...
}
explanation on how or (||) works JavaScript OR (||) variable assignment explanation

Get an object just by a property value

Let´s assume I have an object property which is passed into a function. In this case 'name' is filled with 'myObject.name' (which has the value 'Tom') - so basically 'Tom' gets passed into the function as the 'name'
function(name) {
do something //non-essential for my question
}
Is it possible to get the object, where 'Tom' is the property of, just by having the information 'Tom'? Basically I´m looking to get myObject.
Thanks :)
No, that's not possible.
All that the function knows is that one of its parameters was pointed to the string "Tom", not what else points to that string somewhere else in memory.
You can store objects within an array, filter the array to match property name of object to parameter passed to function using for..of loop, Object.entries(), which returns an array of property, values of an object.
const data = Array();
const setObjectPropertyName = _name => {
data.push({[_name]:_name});
return data
}
const getObjectByPropertyName = prop => {
let res = `${prop} property not found in data`;
for (let obj of data) {
for (let [key] of Object.entries(obj)) {
if(key === prop) return obj;
}
}
return res;
}
let s = setObjectPropertyName("Tom");
let g = getObjectByPropertyName("Tom");
let not = getObjectByPropertyName("Tome");
console.log(s,"\n", g, "\n", not);
Disclaimer: you absolutely should not do this. I'm only posting this because it is in fact possible (with some caveats), just really not advisable.
Going on the assumption that this is running in the browser and it's all running in the global scope (like in a script tag), you could technically iterate over the window object, check any objects in window for a name property and determine if their name property matches the name passed to your function.
var myObject = {
name: 'Tom',
thisIs: 'so awful',
imSorry: true,
};
function doSomethingWithName(name) {
for (var obj in window) {
var tmp = window[obj];
if (Object(tmp) === tmp && tmp.name === name) {
return tmp;
}
}
}
console.log(doSomethingWithName(myObject.name));

indexOf for array with different objects

I have an array of users.
When I click on button "Add New", I want to add new object to this array only if it doen't exist there:
var newUser = { 'creating': true, 'editMode': true };
if ($scope.users.indexOf(newUser) < 0) {
$scope.users.push(newUser);
}
but indexOf always return -1.
Is this because array contain "different" objects?
I suppose each time you're going to call "Add New", it'll work (hard to say without more code). For the simple reason that each instance of newUser is a different one.
The indexOf calls check for exactly this instance of newUser. It doesn't check the property values, just for the reference to the instance.
e.g. :
var user = {a : "b"};
var users = [];
users.push(user);
users.indexOf(user); // returns 0, reference the user created at the top, inserted beforehand
user = {a : "b"};
users.indexOf(user); // returns -1, reference the user created just above, not yet inserted
If you want to check for instance, you'll have to make a check on a property (name, id, ...)
If you want to have a collection of unique values you should use ECMASCRIPT-6 Set
If you need to stay legacy, otherwise, you need to use arrays...
var Set = (function() {
function Set() {}
Set.prototype.has = function(val) {
return !!this._list.filter(i => i.id === val.id).length;
};
Set.prototype.get = function(val) {
if(!val) {
return this._list;
}
return this._list.filter(i => i.id === val.id).pop();
};
Set.prototype.add = function(val) {
if(!this.has(val)) {
this._list.push(val)
}
return this;
}
return Set;
})();

For...in loop filtering only objects

Is there a way to filter out everything inside of a for...in loop to only get the objects?
I'm writing a function to loop through nested objects to find certain pieces of data and then save it to localStorage.
Example:
var equipped = {
data: [the rest of the properties of equipped go here],
tool: {
data: [the rest of the properties of tool go here],
axe: {
data: [the rest of the properties of axe go here],
iron: {...},
steel: {...}
}
}
}
The tool/axe/metal properties are all generated dynamically and is different each time. Inside the metal properties is the data I'm trying to save. I would normally just loop through the array if I was trying to access the data (Using knockoutjs for binding, it's much easier to just foreach the data array), but I'm using the variable from a for...in loop to build the rest of the tree in my localStorage object before stringifying it.
How I'm reading the object:
for (var type in equipped) {
if (check goes here) {
savedValue.equipped[type] = {};
for (var category in equipped[type]) {
etc etc...
}
}
}
I understand that everything is an object type so I can't just do an instanceof or typeof on a defined object to filter them out. Is there another easy way to do it inside of an if statement or do I have to make each step of the tree from a constructor so I can instanceof RealObject?
Either of these should do well:
function isObject(val) {
if (val === null) { return false;}
return (typeof val === 'object');
}
or
function isObject(obj) {
return obj === Object(obj);
}
or
// this only works with object literals
function isObject(val) {
return (!!val) && (val.constructor === Object);
};
this last one, gives me the following:
console.log(isObject()); // false
console.log(isObject([])); // false
console.log(isObject(new Date)); // false
console.log(isObject({})); // true
console.log(isObject(null)); // false
console.log(isObject(true)); // false
console.log(isObject(1)); // false
console.log(isObject('someValueString')); // false
so, something like:
for (var type in equipped) {
if (isObject(type)) {
savedValue.equipped[type] = {};
for (var category in equipped[type]) {
etc etc...
}
}
}
Note: You can also try the following, but I have not used it. So you'd have to go thru your use cases.
Object.getPrototypeOf
Here is the code to check whether the variable is object or not:
function isJsonObject( obj ) {
// Must be an Object.
// Because of IE, we also have to check the presence of the constructor property.
// Make sure that DOM nodes and window objects don't pass through, as well
if ( !obj || obj.toString() !== "[object Object]" || obj.nodeType || obj.setInterval ) {
return false;
}
// Not own constructor property must be Object
if ( obj.constructor
&& !obj.hasOwnProperty("constructor")
&& !obj.constructor.prototype.hasOwnProperty("isPrototypeOf")) {
return false;
}
// Own properties are enumerated firstly, so to speed up,
// if last one is own, then all properties are own.
var key;
for ( key in obj ) {}
return key === undefined || obj.hasOwnProperty( key );
}
There's an old hack for type detection I've used previously.
var classChecker = {}.toString;
classChecker.call({});
classChecker.call(function() {});
classChecker.call([]);
// etc...
// More immediately relevant use:
var savedValue = {
equipped: {}
};
var objectString = classChecker.call({});
for (var type in equipped) {
if (classChecker.call(equipped[type]) === objectString) {
savedValue.equipped[type] = {};
for (var category in equipped[type]) {
// ...
}
}
}
console.log(savedValue);
See http://plnkr.co/edit/nKLQsOdcurrpUCg7cOoJ?p=preview for a working sample. (open your console to view output)

Dynamically create sub-objects and arrays when needed

I have an object created from JSON via AJAX from the server. The object has several sub-objects in an array, e.g.:
obj.subObj1[0].value="abc";
obj.subObj1[1].value="abc";
obj.subObj2[0].value="abc";
Now I want to set some values in this object but I dont know if they already exist.
obj.subObj1[0].value="new Value"; // No Problem
obj.subObj2[1].value="new Value2"; // Problem because obj.subObj2[1] is no Object.
I would need to do obj.subObj2[1]={} first.
Because I have this problem very often I am looking for method to automate this. A method or class which does automatically create the needed object (or array if I use an integer).
It should be able to handle an infinite depth of such sub-objects. Like this:
var obj = TheObject();
obj.sub1.sub2[10].sub3[1].sub4='value';
Now automatically all needed sub-objects and arrays should be created.
Cannot really guarantee anything about cross-browser compatibility, but how about trying this on for size (works in Chrome):
// Safely sets value property of index of an array of an object.
function setObj(obj, subObjName, index, val) {
// Ensure the object exists
if (typeof obj == 'undefined') {
obj = new Object();
}
// Ensure the array property exists
if (typeof obj[subObjName] == 'undefined') {
obj[subObjName] = new Array();
}
// Ensure the array properties index exists
if (typeof obj[subObjName][index] == 'undefined') {
obj[subObjName][index] = {};
}
// Set the value
obj[subObjName][index].value = val;
// Return the object
return obj;
}
Example use:
<script type="text/javascript">
var obj;
obj = setObj(obj, "something", 1, "val");
setObj(obj, "something", 0, "someValue");
alert(obj.something[1].value);
alert(obj.something[0].value);
</script>
If you can assume that the referenced item in the array will be either undefined or an object it simplifies things. Of course the simple (non-automatic) way would be something like this:
if (!obj.subObj2[1]) obj.subObj2[1] = {};
obj.subObj2[1].value = "new Value2";
A not-very generic function to do it for you would be:
function setArrayObjectProp(arr, index, prop, val) {
if (!arr[index])
arr[index] = {};
arr[index][prop] = val;
}
// called as
setArrayObjectProp(obj.subObj2, 1, "value", "new Value2");
heloo
try testing the type of the array item first if its not object then equal it to the new object format {value:"new Value2"}
if(typeof(obj.subObj2[1])!='object')
{
obj.subObj2[1] = {value:"new Value2"};
}
else
{
obj.subObj2[1].value = "new Value2";
}

Categories