I am receiving a data object from an api where some of its properties may have a value of null. I want to create a function that returns the object but for the properties that have a null value there is a "-" instead. I have tried:
const hyphenOrContent = movie => {
return Object.values(movie).map(val => {
return val === null ? "-" : val
});
}
but this only returns an array of the values. I've read that it's better not to use a for in loop so I would like to avoid using one if possible. Any help appreciated!
Map the object's entries, turning nulls into -s, then use Object.fromEntries to turn the array of entries into an object:
const hyphenOrContent = movie => Object.fromEntries(
Object.entries(movie).map(
([key, val]) => ([key, val === null ? "-" : val])
)
);
Just loop over the Object and alter the properties.
const hyphenOrContent = movie => {
Object.entries(movie).forEach(([key, val]) => {
if (val === null) movie[key] = '-';
});
};
var a = {
foo: null,
bar: '123',
baz: null
}
hyphenOrContent(a);
console.log(a);
If you do not want to alter the original, you can clone it.
Related
This question already has answers here:
In JavaScript, how to conditionally add a member to an object?
(29 answers)
Conditionally set an object property
(7 answers)
How to conditionally add properties to a javascript object literal
(8 answers)
Closed 8 months ago.
I want to create a property on an object conditionally.
The idea is to ensure the property doesn't exist (so not just null) if it has no value.
What I'm doing right now:
// comes from users
req.query = {
foo: true
}
// my object which will contains allowed properties IF EXISTS
const where = {}
if (req.query.foo) {
where.foo = req.query.foo
}
if (req.query.bar) {
where.bar = req.query.bar
}
console.log(where)
It's really boring to repeat this for every different property...
Is there a way to do it in one line?
EDIT:
I don't want to get all properties from req.query
Create object property obj.foo if value exists (or any other condition)
&& operator returns second element if the first boolean condition is fulfilled
es6 spread operator ... does what it does)
const value = 'bar'
const empty = undefined
const obj = {
...value && { foo: value }, // read ...(value && { foo: value }) parenthesis are not necessary
...empty && { empty },
...(100 > 0) && { condition: 'true' },
...(100 < 0) && { condition: 'false' },
}
console.log(obj)
You could do:
const merged = {...where, ...req.query};
Try this:
const elements = ["foo", "bar"];
elements.forEach(el => {
if (req.query[el]) {
where[el] = req.query[el];
}
});
You can simply write it in one line like this :
let where = {};
if (req.query.foo) where = {...where, foo : req.query.foo };
if (req.query.bar) where = {...where, bar : req.query.bar };
I hope that it helps.
If you want a simple one liner (maybe less readable), you can do:
Object.keys(req.query).forEach(key => req.query[key] && (where[key] = req.query[key]));
If you're okay adding a pluck function, you could do it like this:
const req = { query: { baz: '1', foo: '3' } };
const where = {};
const pluck = (keys, obj) =>
keys.reduce((a, k) => typeof obj[k] === 'undefined' ? a : Object.assign(a, { [k]: obj[k] }), {});
const add_foo_bar = (where, query) =>
Object.assign({}, where, pluck(['foo', 'bar'], query));
const res = add_foo_bar(where, req.query);
console.log(res);
Trying to modify object value in array on condition on some arrays the override does not work, here is my snippet
const removeAction = (target, array, name) => {
let mutation = JSON.parse(JSON.stringify(array));
mutation.map( obj => {
if(obj.value === target.value) {
console.log(obj)
obj.checked = false
}
return obj
})
console.log(mutation)
removeCallback(mutation, name)
}
and I get back the original object in array. How do I debug this issue?
const modifiedArray = JSON.parse(JSON.stringify(array)).map(...
Map always returns new instance of array. So either assign that mutated map to some variable or loop over and mutate the original array.
You could take the mapped objects with destructuring the object and an updated property.
const
removeAction = (target, array, name) => {
removeCallback(array.map(obj => ({
...obj,
checked: obj.value === target.value ? false : obj.checked
})), name)
};
I've been working on an event handler to sync inputs with the state and came up with this solution:
https://gist.github.com/jadeallencook/678869f988bd65378d819496c4343e78
The handler pushes the value to the end point using the string and merges the result with the current state but I have to use lodash to accomplish it, is there anyway to do it in vanilla?
A reduce will produce a generic solution:
const path = 'foo-bar-num';
const paths = path.split('-');
const object = {};
const value = 'Woo hoo!';
paths.reduce(([object, value], path, idx) => {
object[path] = idx === paths.length - 1 ? value : {};
return [object[path], value];
}, [object, value]);
console.log(object)
Alternatively you can try lodash set function to set value for deeply nested object.
import set from 'lodash/set'
let path = 'foo-num';
const paths = path.split('-').join('.')
const value = 'some value';
set(object, paths, value)
You could store the last key and reduce only the keys before. Ath the end store the previous value and assign the new value.
function setValue(object, keys, value) {
var last = keys.pop(),
temp = keys.reduce((o, k) => o[k] = o[k] || {}, object);
temp.original = !(last in temp) ? null : temp[last];
temp[last] = value;
}
const
object = {},
path = 'foo-bar-num',
value = 'Woo hoo!';
setValue(object, path.split('-'), value);
console.log(object);
Is there a way to optimize the following with ES5 / ES6?
var obj = [];
var set;
for (var key_s in data1) {
set = false;
for (var key_s2 in data2) {
if (data1[key_s].id === data2[key_s2].id) {
obj.push({'id': data1[key_s].id,
'key': data1[key_s].key,
'value': data2[key_s2].value})
set = true;
break;
}
}
if (!set)
obj.push({'id': data1[key_s].id,
'key': data1[key_s].key,
'value': "EMPTY"})
}
I want to have an object which contains all keys of data1 and if a pair got the same id like the one in data2, it should take its value, otherwise it should become 'EMPTY'. Or maybe is there a way to use Object.assign with some special parameters or something?
You could use Map for data2 and use Array#map with data1 and the possible value of data2.
var map = new Map(data2.map(o => ([o.id, o]))),
obj = data1.map(({ id, key }) => ({ id, key, value: map.has(id)
? map.get(id).value
: 'EMPTY'
}));
This is pretty es6'ed. map over data1, the .find will return the matching object if one exists or else return undefined. set key_s.value to either the key_s2 value or "EMPTY" and then return the key_s object. You will end up with an array of objects. This assumes that data1 and data2 are arrays of objects, that is how your example was written so I figured it was the case.
let obj = data1.map(key_s => {
let newValue = data2.find(key_s2 => key_s.id === key_s2.id)
key_s.value = newValue ? newValue.value : "EMPTY"
return key_s
})
})
You could do it with Array#map, Array#find and Object.assign. By specifying the value in the first parameter of Object.assign, you can set a default to be overridden by the object from data2.
var obj = data1.map(obj1 => {
const obj2 = data2.find(obj2 => obj1.id === obj2.id);
return Object.assign({ value: 'EMPTY' }, obj1, obj2);
});
Using spread properties, that Object.assign could be changed to:
{ value: 'EMPTY', ...obj1, ...obj2 }
Have an array which contains a no of json .
[{linkValue:"value1"},{linkValue:"value2"},{linkValue:"value3"},{linkValue:"value4"},{linkValue:"value5"}]
Note that each Json have same key . I want to convert this array into a single json like
{linkValue1:"value1",linkValue2:"value2",linkValue3:"value3",linkValue4:"value4",linkValue5:"value5"}
one thing i also need to know . my array is also inside a json how i get this arry from that json ?
My initial json is
{name:"value",age:"value",linkValue:[[{linkValue:"value1"},{linkValue:"value2"},{linkValue:"value3"},{linkValue:"value4"},{linkValue:"value5"}]
]}
I'm expcting my final json look like :
{name:"value",age:"value",linkValue1:"value1",linkValue2:"value2",linkValue3:"value3",linkValue4:"value4",linkValue5:"value5"}
can anyone please help me
Use Array.forEach and add properties to an empty object:
let source = {name:"value",age:"value",linkValue:[[{linkValue:"value1"},{linkValue:"value2"},{linkValue:"value3"},{linkValue:"value4"},{linkValue:"value5"}]]};
// Copy the array in a variable
let yourArray = source.linkValue[0];
// Delete the original array in the source object
delete source.linkValue;
yourArray.forEach((item, index) => {
source["linkValue" + (index + 1)] = item.linkValue
});
console.log(source); // Should have what you want
Using reduce API,
let targetObj = srcArr.reduce((accumulator, value, index)=>{
accumulator['linkValue'+(index+1)] = value.linkValue;
return accumulator;
}, {});
[{linkValue:"value1"},{linkValue:"value2"},{linkValue:"value3"},{linkValue:"value4"},{linkValue:"value5"}]
This is javascript Array contains multiple javascript object.
{linkValue1:"value1",linkValue2:"value2",linkValue3:"value3",linkValue4:"value4",linkValue5:"value5"}
If you need structure like this,Then define a single javascript object and add linkvalue1,linkvalue2 etc. as a member of that object and then add it to javascript Array.
Give this a try.
myObj.linkValue = myObj.linkValue.map((obj, index) => ({ [`linkValue${index + 1}`]: obj.linkValue }))
Solution with reduce
// HELPER FUNCTIONS
// pick properties from object with default value
function pick (props, sourceObj, defaultValue) {
return props.reduce(
(obj, prop) =>
Object.assign(obj, { [prop]: sourceObj[prop] || defaultValue }),
{}
)
}
// get property value or default
function propOr (propName, obj, defaultValue) {
return obj[propName] || defaultValue
}
// flatten nested array
function flattern (nestedArray) {
return nestedArray.reduce((flat, innerArray) => flat.concat(innerArray), [])
}
// LINKS BUILDER based on REDUCE
function buildLinks (linksArray) {
return linksArray.reduce((accumulator, item, index) => {
accumulator['linkValue' + (index + 1)] = item.linkValue
return accumulator
}, {})
}
// TRANSFORMATION FUNCTION - takes json and produce required output
function transform(json) {
return Object.assign(
{},
pick(['name', 'age'], json, null),
buildLinks(flattern(propOr('linkValue', json, [])))
)
}
// EXECUTION
const result = transform(source)
PS> You can use libraries like Lodash or Ramda and replace helper functions defined by me with ones from library