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
Related
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));
Say I want to assign a value like this:
x.label1.label2.label3 = someValue;
// or equivalently:
x['label1']['label2']['label3'] = someValue;
This works as long as x.label1.label2 is defined but runs into reference errors otherwise. Which makes sense of course. But is there an easy way to assign this anyway where it simply creates the necessary nested objects?
So for example, if x equals { label1: {}, otherLabel: 'otherValue' } I want to update x to become { label1: { label2: { label3: someValue } }, otherLabel: otherValue }
I think I might be able to write a function myself, but is there a language feature or standard library function that does this?
is there a language feature or standard library function that does this
No. You have to write your own function or use a library that provides such functionality.
Related: How to set object property (of object property of..) given its string name in JavaScript?
This is partially possible using the Proxy class. You can wrap your object in a Proxy and override the get trap to create another copy of the same proxy when you access a nonexistent property. This lets you recursively create "deep" properties. An example:
let traps = {
get: function (target, name) {
if (!(name in target))
target[name] = new Proxy({}, traps);
return target[name];
}
};
let x = new Proxy({}, traps);
Then you would use x like any object, except it has this special behavior:
x.label1.label2.label3 = 'foo';
which creates a nested hierarchy of objects. However, note that this will create an object even if you access a nonexistent property. Thus, you will have to use the in keyword to check if it really contains a given property.
I think you should indeed use a custom function such as:
function assignByPath(obj, path, value) {
var field = path.split('>'),
last = field.pop();
field.reduce(
function(node, f) {
return node[f] = node[f] instanceof Object ? node[f] : {};
}, obj
)[last] = value;
}
var myObj = {};
assignByPath(myObj, 'label1>label2>label3', 'someValue');
console.log(myObj);
Theoretically, you could also override Object.prototype, which would allow you to do:
myObj.assignByPath('label1>label2>label3', 'someValue');
But I would not recommend that.
You can use Array.prototype.shift(), Object.assign(), recursion
var x = {
label1: {},
otherLabel: "otherValue"
};
var nestprops = (props, value, obj, o, curr = props.shift()) => props.length
? nestprops(props, value, (Object.assign(obj, {[curr]: {}}) && obj[curr]), o)
: ((!value || value) && (obj[curr] = value) && o);
console.log(nestprops(["label1", "label2", "label3"], "someValue", x, x));
Check length of keys inside label1 object if its equal to 0 then modify it to your desired object.
Here is a snippet, hope it helps.
var obj = { label1: {}, otherLabel: 'otherValue' };
if(Object.keys(obj.label1).length == 0 ) {
obj.label1 = { label2: { label3: "value3" } };
}
console.log(obj);
I have an object and I want to use object property value as key (simplified):
var App = function() {
this.settings = {
'tetris': {
title: 'Tetris'
},
'galaxian': {
title: 'Galaxian'
}
};
this.gameName = 'tetris';
this.request = {
this.settings[this.gameName].title: 'THIS KEY IS INVALID' // :(
}
};
I know I could assign it as:
this.request[ this.settings[this.gameName].title ] = 'Valid...';
But I wonder if I can define the property name using the object property value?
I am afraid, what you mean is not possible. You can not use a variable as a key in an object literal like this:
var key = "somekey";
var obj = {key: "value"}
The above code will result in an object that has the key key.
You can only use a variable to define an object element like this:
var key = "somekey";
var obj = {};
obj[key] = "value"
Then the object get's an element with the key somekey
EDIT: As stated in the comments, in ECMAScript 6 the support for computed properties in object literals got introduced. However the browser support for the computed properties in object literals is very slim (you can look it up here under syntax -> object literals). For example IE 11 has no support for it, neither has Chrome 43.
Computed property names will be introduced in ECMAScript edition 6, they're in the current draft, so you can do:
this.request = {
[this.settings[this.gameName].title]
}
They're reasonably well supported now, see MDN for more detail.
You can't define literal objects with computed property names; you have to assign them.
In other words, you can either define a literal object using {...} notation if the property name is well-known, or assign values into keys in a map using x[prop] = v notation if the property name is computed.
Think of your JS objects as being either objects or maps, but not both. If the JS object has well-known property names then it's acting as an object:
var obj = {
wellKnownPropertyName = 'value';
};
var value = obj.wellKnownPropertyName;
But if the property name is computed then it's not really a property of an object but more like a key in a map, and should be assigned (and read) as such:
var map = {};
var key = getUnknownKeyFromSomewhere();
map[key] = 'value';
var value = map[key];
I'm wanting to replace the following code to no longer rely on the _.each() function of underscore.js or lodash.js:
function fset(data) {
_.each(dataDefault, function(item, key) {
var val = ( data[key] ? data[key] : dataDefault[key] );
$rootScope.meta[key] = val;
});
};
Ideally, I want to use a vanilla JavaScript for loop, but I don't understand how the _.each() function in underscore/lodash works to replace it...
Something like:
for(var i=0; i<data.length;i++) {
var val = ( data[key] ? data[key] : dataDefault[key] );
$rootScope.meta[key] = val;
}
But, I don't know how to get the key and item in this way...
dataDefault looks like:
var dataDefault = {
title: null,
description: null
};
An example of calling the function would be:
meta.fset({
title: 'Hello world',
description: 'DESC'
});
Try this:
Object.keys(dataDefault).forEach(function (key) {
var value = dataDefault[key]
// iteration code
})
With for..in you have to use hasOwnProperty to exclude inherit properties.
So, if I'm interpreting your logic correctly, what you're trying to do is loop through the keys in your defaults object, and if the object you're inspecting doesn't have that key, you want to add that key to the object and assign its value to the default value, is that correct? Any limitations on browser level?
The quickest way to do it if you know for sure what the default data object looks like would be to use a for..in loop:
var data = {}; // or wherever you get it from)
for (var key in defaultData){
data[key] = data[key] || defaultData[key];
}
That assumes that data.key is non-null and non-false. If false or null is a valid value (and your default is not null or false), then you'll want to make a bit more effort at ascertaining the existence of the key and type of the value. But based on your example, you're not worried about that.
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";
}