Javascript Function: Use Variable instead of single Values - javascript

I found here a script. It works fine. But now, I want to use a Variable instead of single values.
Here the original script:
const customData = {
"func":"bri",
"oid":"ID",
"onVal":1,
"offVal":0,
"...":"..."
}
const getSubset = (obj, ...keys) => keys.reduce((a, c) => ({ ...a, [c]: obj[c] }), {});
const Light.bri = getSubset(customData, "oid", "onVal", "offVal");
Result (OK):
bri: {
offVal: 0,
oid: "objekt-ID",
onVal: 1
},
Now I want to do define the keys in a variable, ideally as a object. But this do not work.
const params = {bri: "oid, onVal, offVal"};
const Light.bri = getSubset(customData, params.bri);
Result (NOK):
bri: {
oid, onVal, offVal: undefined
},
description: "Deckenspots"
}
what changes do I have to make?

Define the bri property as an array of strings. That way you can use the spread syntax (...) to pass the strings as individual arguments.
const params = {bri: ["oid", "onVal", "offVal"]}; // bri is now an array.
const Light.bri = getSubset(customData, ...params.bri); // Notice the ... before params.bri

Related

Check for a key inside In array of objects

I am trying to find the best way to check whether an object key is present inside multiple objects present in an array which will provide a boolean as output
[{alert:hi},{alert:bye},{}]
From the above example basically what I am trying to achieve is if any one object is missing the alert object key the output should be as false or anything
You can iterate your array with every(). Something like this:
const objects = [{alert:'hi'},{alert:'bye'},{}];
const every = objects.every(obj => obj.hasOwnProperty('alert'));
console.log(every);
You can use the Array#some method and check if at least one element is undefined
const isAlertMissing = (array) => array.some(elem => elem.alert === undefined)
const objs1 = [{alert: "foo"},{alert: "foo"},{}]
const objs2 = [{alert: "foo"},{alert: "foo"}]
console.log(isAlertMissing(objs1))
console.log(isAlertMissing(objs2))
You can use every to check all items and some with Object.keys for finding a key in the inner objects.
const data = [{alert:"hi"},{alert:"bye"},{}]
const result = data.every(item => Object.keys(item).some(key => key === "alert"));
console.log(result) //false
EDIT
some with Object.keys is kind of roundabout, so we can use hasOwnProperty instead.
const data = [{alert:"hi"},{alert:"bye"},{}]
const result = data.every(item => item.hasOwnProperty("alert"));
console.log(result) //false
Array#some will succeed as soon a match is found, making it more efficient than Array#every.
const test = (data, propName) =>
!(data.some((el) => !el.hasOwnProperty(propName)))
const data1 = [ {alert:'hi'}, {alert:'bye'}, {}]
const data2 = [ {alert:'hi'}, {alert:'bye'}]
console.log(test(data1, 'alert')) // false
console.log(test(data2, 'alert')) // true
Or:
const test = (data, propName) => {
for(let el of data) {
if(!el.hasOwnProperty(propName))
return false
}
return true
}
const data1 = [ {alert:'hi'}, {alert:'bye'}, {}]
const data2 = [ {alert:'hi'}, {alert:'bye'}]
console.log(test(data1, 'alert')) // false
console.log(test(data2, 'alert')) // true

Smarter way of using filter and map instead of filter and loop

I want to create a smarter way of coding of the following example. Important is that each loop (for activeFilters) needs to be fully done, before we want to return the filtersTest.
const createFilters = async () => {
const filtersTest = [] as any
// Only create active filters by checking count.
const activeFilters = getComponentFilter.value.filter(function(item) {
if (item.items) {
return item.items.some((obj) => obj.count)
}
});
// Loop through the active filters and push arrays into the object.
for(let i = 0 ; i < activeFilters.length; i++) {
const options = await createFilterOptions(activeFilters[i].id, activeFilters[i].items);
const array = {
defaultValue: null,
id: activeFilters[i].id,
value: 'nee',
label: activeFilters[i].label,
options: options,
}
filtersTest.push(array)
}
return filtersTest;
}
First of all, it should be clear that createFilters is not going to return the array, but a promise that will eventually resolve to that array.
With that in mind, you can reduce your code a bit, using Promise.all, the ?. operator, destructuring parameters, and shorthand property names in object literals:
const createFilters = () => Promise.all(
getComponentFilter.value.filter(({items}) =>
items?.some((obj) => obj.count)
).map(({id, label, items}) =>
createFilterOptions(id, items).then(options => ({
defaultValue: null,
id,
value: 'nee',
label,
options
}))
)
);

Selectively Destructure an object, based on key name

Let's say I have this object:
const someProps = { darkMode: true, underlineMistakes: false, spellingView: (...), grammerView: (...) };
I do not necessarily know the names of any of the props, except that 1+ end in 'View'.
and I want to only destructure the keys that end in 'view', which I'd like to do something like:
const propsEndingInView = Object.keys(someProps).filter(prop => !prop.endsWith('View');
const {
...nonViewProps, // darkMode, underlineMistakes
propsEndingInView // {spellingView: (...), grammerView: (...)}
} = someProps;
I need to somehow separate the two kinds of props, preferably while
I can't think how to do this, or even if it's possible.
Destructuring is just way to get the properties you already know. You can't do this with destructuring. You can create a custom method to filter out the keys to get a subset of the object
const someProps = {
darkMode: true,
underlineMistakes: false,
spellingView: 'spellingView',
grammerView: 'grammerView'
};
const subset = Object.fromEntries(
Object.entries(someProps).filter(([k]) => k.endsWith('View'))
)
console.log(subset)
This cannot be done by destructuring, but you can write some code to do it. For example:
const extract = (obj, regex) =>
Object
.entries(obj)
.filter(([k]) => (typeof k === 'string') && regex.test(k))
.reduce((out, [k, v]) => (
out[k] = v,
out
), {})
const someProps = { darkMode: true, underlineMistakes: false, spellingView: '(...)', grammerView: '(...)' };
const propsEndingInView = extract(someProps, /View$/)
console.log(propsEndingInView)
If I understand correctly you want to end up with an object that only contains properties from someProps whose names end in View. You can do something like:
const viewProps = Object.keys(someProps).reduce((props, propName) => {
// Here we check whether propName ends in View
// If it does we add it to the object, if not we leave the object as it is
return propName.match(/View$/) ? { ...props, [propName]: someProps[propName] } : props;
}, {});
Does that help? You can find the documentation about Array.reduce here.

Refactor Javascript ES6

i need help with refactoring below block of code. I was asked to avoid using let and to use const, how can i use constant here as i need to return all the options having possible match id.
const findRecordExists = (options, possibleMatchId) => {
let item;
options.forEach(option => {
option.waivers.forEach(waiver => {
if (waiver.waiverNameId === possibleMatchId) {
item = option;
}
});
});
return item;
};
Example of options would be :
options: [{
name:Abc
waivers: [ {waiverNameId :1}, {waiverNameId:2} ]
}]
Use filter to iterate over the options array, returning whether .some of the waiverNameIds match:
const findRecordExists = (options, possibleMatchId) => {
return options.filter(
({ waivers }) => waivers.some(
({ waiverNameId }) => waiverNameId === possibleMatchId
)
);
};
Or, if you don't like destructuring:
const findRecordExists = (options, possibleMatchId) => {
return options.filter(
option => option.waivers.some(
wavier => wavier.waiverNameId => waiverNameId === possibleMatchId
)
);
};
Since the result is being immediately returned from the findRecordExists function, there isn't even any need for an intermediate item (or items) variable.
That's okay.
Using const to declare an identifier only makes the value of the identifier unchangeable if the value of the identifier is a JavaScript primitive e.g a number or a boolean.
If the value of the identifier is an object or an array (an array is a type of object in JavaScript), using const to declare it doesn't mean that the value of that object identifier cannot be changes. It only means that the identifier cannot be reassigned.
To refactor your code using const, use the code listing below
const findRecordExists = (options, possibleMatchId) => {
const optionsWithPossibleMatches = [];
options.forEach(option => {
option.waivers.forEach(waiver => {
if (waiver.waiverNameId === possibleMatchId) {
optionsWithPossibleMatches.push(option);
}
});
});
return optionsWithPossibleMatches;
};
If you want to skip intermediate steps of creating variables to store each option that matches your condition, you can use the filter method as prescribed by #CertainPerformance
You can re-factor with using find method. This will simplify and avoids the item variable.
const options = [
{
name: "Abc",
waivers: [{ waiverNameId: 1 }, { waiverNameId: 2 }]
}
];
const findRecordExists = (options, possibleMatchId) =>
options.find(option =>
option.waivers.find(waiver => waiver.waiverNameId === possibleMatchId)
);
console.log(findRecordExists(options, 2));
console.log(findRecordExists(options, 3));

modify a property of an object in the functional way

In javascript programming in the functional way is a great benefit. I'm trying to modify a property of an object contained in an array of objects in the functional way that means that the item that is the object passed in the map function cannot be modified. If I do something like this:
const modObjects = objects.map((item) => {
item.foo = "foo" + 3;
return item;
});
this is not functional because item is modified inside the function. do you know any other approach to this problem?
A new (ES6) way that is really immutable and in the spirit of functional programming:
// A. Map function that sets obj[prop] to a fixed value
const propSet = prop => value => obj => ({...obj, [prop]: value})
// B. Map function that modifies obj.foo2 only if it exists
const foo2Modify = obj =>
obj.hasOwnProperty('foo2') ? {...obj, foo2: 'foo ' + obj.foo2} : obj
// Usage examples of A and B
const initialData = [{'foo': 'one'}, {'foo2': 'two'}, {'foo3': 'three'}]
const newData1 = initialData.map(propSet('foo2')('bar')) // Set value
const newData2 = initialData.map(foo2Modify) // Use a modify function
console.log(initialData) // Initial data should not change
console.log(newData1) // Each object should contain the new fixed foo2
console.log(newData2) // Modify foo2 only if it exists in initial data
You could use Object.assign to create a copy of the item obj and return that from the map callback.
Object.assign()
The Object.assign() method is used to copy the values of all enumerable own properties from one or more source objects to a target object. It will return the target object.
Here is an example
let data = [
{"foo": "one"},
{"foo": "two"},
{"foo": "three"}
]
let newData = data.map( item => {
let itemCopy = Object.assign({}, item);
itemCopy.foo = "foo " + item.foo;
return itemCopy;
})
console.log(data)
console.log(newData)
You can also do it like this:
const modObjects = objects.map((item) => {
return { ...objects, foo: "foo" + 3; };
});
The reason that this: objects.map((item) => { ...destSchema, foo: "foo" + 3; }); doesn't work is that they made it this way to make the JS interpreter understand whether it is a scope or an object. You MUST use return
In modern JavaScript you can use spread operator on object inside of an object literal for this:
const modObjects = objects.map(
item => ({...item, foo: item.foo + 3})
)
Notice parentheses () around object literal. They are needed to disambiguate object literal {} from code block {} in lambdas. Another way is to use code block with return:
const modObjects = objects.map(
item => { return {...item, foo: item.foo + 3} }
)
I have extended #Dimitrios Tsalkakis answer to change property with a callback function.
Example: https://repl.it/#robie2011/ts-set-property-functional
Typescript:
function mapProperty<T>(prop: string){
return (cb: (propValue: any) => any) => (obj: any) => ({...obj, [prop]: cb(obj[prop])}) as (T)
}

Categories

Resources