Hello Im stuck with constructing a new object based on the backend respond.
Here is the respond that i've receive
acl:[
{
"user_type":5,
"user_id":"c7e5cb45ba764ad7ad29b5bdd4f12128",
"user_name":"John",
"view":true,
"modify":false,
"remove":false,
"modify_acl":false
},
{
"user_type":5,
"user_id":"f673beac0245462f8c71066536049e72",
"user_name":"Allan",
"view":true,
"modify":true,
"remove":true,
"modify_acl":false
}]
The requirement was to filter the respond to remove all of the properties with false value and construct a new array that hold the access control value (acl).The expected new object will be like this:
[
{
"userType":5,
"label":"c7e5cb45ba764ad7ad29b5bdd4f12128",
"value":"John",
"acl":[
{"value":"view", "label":"View"}
]
},
{
"userType":5,
"label":"f673beac0245462f8c71066536049e72",
"value":"Allan",
"acl":[
{"value":"view", "label":"View"},
{"value":"modify", "label":"Modify"},
{"value":"remove", "label":"Remove"}
]
}
]
Currently i'm using reduce method to remove all the false value. But I'm stuck to construct the expected result.
You could check the type of the property and take boolean for assigning a new label/value pair and omit false values. Otherwise take the key value pair and assign it to the actual object.
Array#map is actually the better method of choice, because it returns an array, which is wanted.
By using Array#reduce, the accumulator would never change, because it would be an array.
var acl = [{ user_type: 5, user_id: "c7e5cb45ba764ad7ad29b5bdd4f12128", user_name: "John", view: true, modify: false, remove: false, modify_acl: false }, { user_type: 5, user_id: "f673beac0245462f8c71066536049e72", user_name: "Allan", view: true, modify: true, remove: true, modify_acl: false }],
result = acl.map(o => {
var r = {},
acl = [];
Object.entries(o).forEach(([k, v]) => {
if (typeof v === 'boolean') {
v && acl.push({ value: k, label: v });
} else {
r[k] = v;
}
});
return Object.assign(r, { acl });
});
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Related
I have an array of object that is coming from some api.The data i am getting is like this. It has multiple values but i only want to show the user which access he has. Suppose a user have only read access so i want to show the user read key.
[
{
admin: false,
createdAt: "2022-08-21T05:32:20.936Z",
id: 8,
read: false,
write: true,
},
];
So, i want to get only the key value pair from this array which has true values so i can show the keys using Object.keys().
expected result
[{write:true}]
I have tried different array methods but didn't succeed, here how i was thinking to solve this problem but it's only returning last element value.
item.map(tab => {
return Object.keys(tab).reduce((acc: string, key) => {
if (tab[key]) {
acc[key] = tab[key];
}
return acc;
}, {});
}),
You can get rid of reduce by creating an object from filtered entries. Then just filter by true values.
data = [
{
admin: false,
createdAt: "2022-08-21T05:32:20.936Z",
id: 8,
read: false,
write: true,
},
{
admin: false,
createdAt: "1234",
id: 8,
read: true,
write: true,
}
];
out = data.map(item => Object.fromEntries(Object.entries(item).filter(([key, value]) => value === true)));
console.log(out)
if (tab[key]) will be applied on any truthy value not just true, for example, not empty string is a truthy value, any number is a truthy value except zero.
So you need explicitly check if the value equal to true by if (tab[key] === true)
const data = [
{
admin: false,
createdAt: "2022-08-21T05:32:20.936Z",
id: 8,
read: false,
write: true,
},
];
const result = data.map(tab => {
return Object.keys(tab).reduce((acc, key) => {
if (tab[key] === true) {
acc[key] = tab[key];
}
return acc;
}, {});
})
console.log(result)
For shorthand use can use
const result = data.map(tab => Object.entries(tab).reduce((acc, [key, value]) => ({ ...acc, ...(value === true && { [key]: value }) }), {}));
You can get the keys you want by changing the 2nd parameter of the keyFilters function.
let tabs = [
{admin: false,createdAt: "2022-08-21T05:32:20.936Z",id: 8,read: false,write: true},
{admin: false,createdAt: "2022-08-21T05:32:20.936Z",id: 8,read: true,write: true}
];
let keyFilters = function(values, keys){
let filteredKeys = {}
Object.keys(values).map((key, index)=>{
if (keys.includes(key)){
filteredKeys[key] = values[key]
}
})
return filteredKeys;
}
let filters = tabs.map(tab=>keyFilters(tab, ["read", "write"]))
console.log(filters)
output
0:(2) {read: false, write: true}
1:(2) {read: true, write: true
I need to change a nested variable property. First check if it exists then change it to 'N/A' if necessary. This is what I have.
const json = {
isCat: {
isAvaliable: true,
count: 5
},
isDog: {
isAvaliable: true,
count: 10
},
isFrog: {
isAvaliable: false,
count: null
}
}
const newJson = { ...json }
if(!jsonObj.isCat.count) {
newJson = {...newJson, json.isCat.count: 'N/A'}
}
Im not sure how to set count lets say by goign directly to it and changing the value. It seems simple maybe im missing something.
I can see the value in the if statement but i cant make any changes to the actual property value itself. Basically if a value is null, change it to 'N/A'
Using Object.entries and Object.fromEntries you can map the old object to the new object. If the count property is truthy, i.e. not null then map it through, otherwise shallow copy the element and update the count property with the new "N/A" value. This avoids mutating your original object.
const newJson = Object.fromEntries(Object.entries(json).map(([key, value]) => ([
key,
value.count ? value : { ...value,
count: 'N/A'
}
])));
const json = {
isCat: {
isAvaliable: true,
count: 5
},
isDog: {
isAvaliable: true,
count: 10
},
isFrog: {
isAvaliable: false,
count: null
}
};
const newJson = Object.fromEntries(Object.entries(json).map(([key, value]) => ([
key,
value.count ? value : { ...value,
count: 'N/A'
}
])));
console.log(newJson);
You can use array reduce method. First get all the keys using Object.keys method. Then traverse the keys and check the count is null or not. If null then change it to 'N/A'.
const json = {
isCat: {
isAvaliable: true,
count: 5,
},
isDog: {
isAvaliable: true,
count: 10,
},
isFrog: {
isAvaliable: false,
count: null,
},
};
const ret = Object.keys(json).reduce((prev, c) => {
const p = prev;
if (!json[c].count) p[c] = { ...json[c], count: 'N/A' };
else p[c] = { ...json[c] };
return p;
}, {});
console.log(ret);
Another solution with reduce. Beware of it's comma operator in the return value.
const json = {isCat: {isAvaliable: true,count: 5,},isDog: {isAvaliable:true,count: 10,},isFrog: {isAvaliable: false,count: null,},};
const res = Object.keys(json).reduce((pV,cV)=>(json[cV].count==null?json[cV].count='N/A':null,json),{});
console.log(res);
I am having an array with the below items. I need to sort the below array to the array that is shown in sorted items,so that all the value with the rules can be together and the ELIG_DATABASE should be grouped with the ELIG_SERVICE.
const items =[{"name":"ELIG_DATABASE","ready":true},
{"name":"ELIG_RULES_SERVICE","ready":true},
{"name":"ELIG_GATEWAY","ready":true},
{"name":"ELIG_GATEWAY_LATEST","ready":true,"latest":true},
{"name":"ELIG_SERVICE_LATEST","ready":true,"latest":true},
{"name":"ELIG_SERVICE","ready":true},
{"name":"HDXTS","ready":false},
{"name":"RULES_VERSION","ready":true},];
I want to achieve this array so that values in the name property that has rules can be together,gateway things should be together, elig service thing should be together just that ELIG_DATABASE should be grouped together with elig service and then all other values in the name property can be sorted alphabetically.
const sortedItems =[
{"name":"ELIG_GATEWAY","ready":true},
{"name":"ELIG_GATEWAY_LATEST","ready":true,"latest":true},
{"name":"ELIG_RULES_SERVICE","ready":true},
{"name":"RULES_VERSION","ready":true},
{"name":"ELIG_DATABASE","ready":true},
{"name":"ELIG_SERVICE_LATEST","ready":true,"latest":true},
{"name":"ELIG_SERVICE","ready":true},
{"name":"HDXTS","ready":false}
];
I tried using this code but that sorts alphabetically putting ELIG_DATABASE in first position.Could any one please help on how to achieve this array in minimum code as possible.
items.sort((svcA, svcB) => {
const serviceA = svcA.name.toUpperCase();
const serviceB = svcB.name.toUpperCase();
return serviceA.localeCompare(serviceB);
});
You could take the wanted groups first in an array, sort the data and assign the object to the group or to the end of a temp array and get the flat data as result.
var data = [{ name: "ELIG_DATABASE", ready: true }, { name: "ELIG_RULES_SERVICE", ready: true }, { name: "ELIG_GATEWAY", ready: true }, { name: "ELIG_GATEWAY_LATEST", ready: true, latest: true }, { name: "ELIG_SERVICE_LATEST", ready: true, latest: true }, { name: "ELIG_SERVICE", ready: true }, { name: "HDXTS", ready: false }, { name: "RULES_VERSION", ready: true }],
together = [['GATEWAY'], ['RULES'], ['ELIG_DATABASE', 'ELIG_SERVICE']],
groups = { GATEWAY: [], RULES: [], ELIG_DATABASE: [] },
temp = [groups.GATEWAY, groups.RULES, groups.ELIG_DATABASE],
result;
for (let o of data.sort(({ name: a }, { name: b }) => a.localeCompare(b))) {
let target = together.find(a => a.some(v => o.name.includes(v)));
if (target) groups[target[0]].push(o);
else temp.push(o);
}
result = temp.flat();
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
consider the following array.
routingButtonsHighlighter = [
{vehicle: true},
{userAssignment: false},
{relations: false}
];
What is the best way to build a function which can do the following goals?
1) will set all members to false
2) set chosen member to true ( passed as a parameter )
Absent more specific requirements, this is a bit of a choose-your-own-adventure.
(Note: For brevity this code uses ES6 computed property names and destructuring assignment and ES2018 object spread syntax, all of which can be transpiled by TypeScript.)
If each object has exactly one key
...and you want to mutate the original array and objects
const objects = [ { vehicle: true }, { userAssignment: false }, { relations: false } ];
function selectKey(objects, selectedKey) {
for (let obj of objects) {
const [key] = Object.keys(obj);
obj[key] = key === selectedKey;
}
return objects;
}
selectKey(objects, 'userAssignment');
console.log(objects);
...and you want a new array of new objects
const objects = [ { vehicle: true }, { userAssignment: false }, { relations: false } ];
function selectKey(objects, selectedKey) {
const newObjects = [];
for (let obj of objects) {
const [key] = Object.keys(obj);
newObjects.push({ [key]: key === selectedKey });
}
return newObjects;
}
console.log(selectKey(objects, 'userAssignment'))
...but you really like functional style
const objects = [ { vehicle: true }, { userAssignment: false }, { relations: false } ];
function selectKey(objects, selectedKey) {
return objects.map(obj => {
const [key] = Object.keys(obj);
return { [key]: key === selectedKey };
});
}
console.log(selectKey(objects, 'userAssignment'))
If the objects can have more than one key
...and you want to mutate the original array and objects
const objects = [
{ vehicle: true, relations: false },
{ userAssignment: false, vehicle: true },
{ relations: false, userAssignment: false },
];
function selectKey(objects, selectedKey) {
for (let obj of objects) {
for (let key of Object.keys(obj)) {
obj[key] = key === selectedKey;
}
}
return objects;
}
selectKey(objects, 'userAssignment');
console.log(objects);
...and you want a new array of new objects
const objects = [
{ vehicle: true, relations: false },
{ userAssignment: false, vehicle: true },
{ relations: false, userAssignment: false },
];
function selectKey(objects, selectedKey) {
const newObjects = [];
for (let obj of objects) {
const newObj = {};
for (let key of Object.keys(obj)) {
newObj[key] = key === selectedKey;
}
newObjects.push(newObj);
}
return newObjects;
}
console.log(selectKey(objects, 'userAssignment'))
...but you really like functional style
const objects = [
{ vehicle: true, relations: false },
{ userAssignment: false, vehicle: true },
{ relations: false, userAssignment: false },
];
function selectKey(objects, selectedKey) {
return objects.map(obj =>
Object.keys(obj).reduce((newObj, key) =>
({ ...newObj, [key]: key === selectedKey }),
{}
)
);
}
console.log(selectKey(objects, 'userAssignment'))
You can iterate the array with Array.forEach(), get the key using Object.keys(), compare to the selected key, and set the value accordingly:
const routingButtonsHighlighter = [{vehicle: true}, {userAssignment: false}, {relations: false}];
const select = (arr, selectedKey) =>
arr.forEach((o) => {
const key = Object.keys(o)[0];
o[key] = key === selectedKey;
});
select(routingButtonsHighlighter, 'userAssignment');
console.log(routingButtonsHighlighter);
Creating a method for something like this would be highly specialized, so to abstract it, I've decided to write it like this:
function arrayFlagSinglePropertyTrue(key, arrayofobjects) {
for (let i in arrayofobjects) {
let keys = Object.keys(arrayofobjects[i]);
if (keys[0] == key) {
arrayofobjects[i][keys[0]] = true;
} else {
arrayofobjects[i][keys[0]] = false;
}
}
return arrayofobjects;
}
routingButtonsHighlighter = [
{vehicle: true},
{userAssignment: false},
{relations: false}
];
console.log(arrayFlagSinglePropertyTrue("relations", routingButtonsHighlighter));
Although this will get what you require done, its highly specialized and only works if the objects in the array contain one property or at the very least the first property in the object itself is the one you want to set to flag.
Edit: Some advice:
Uniformity in lists helps avoid the issue you have. By structuring your objects with uniform property names and then acting on the values themselves, you no longer require the use of specialized functions or code in order to modify it. At this point you can rely on fundamental programming logic to change the properties efficiently.
If you get the list from some external source and have no control over it, then you may need to either reorganize it yourself. If you can't then making specialized functions/codes is your last resort.
If possible, take something like this:
routingButtonsHighlighter = [
{vehicle: true},
{userAssignment: false},
{relations: false}
];
Organize it into something like this where the actual object properties are uniform:
let betterStructureObject = [
{ propertyName: "vehicle", status: true },
{ propertyName: "userAssignment", status: false },
{ propertyName: "vehicle", status: false },
]
So you can easily loop over it and not have to worry about writing specialized code.
for (let i in betterStructureObject) {
if (betterStructureObject[i].propertyName == "vehicle")
betterStructureObject[i].status = true;
else betterStructureObject[i].status = false;
}
I have a plain JavaScript array of objects, say e.g.
const drawings = [
{
name: "Foo",
category: "widget"
},
{
name: "Bar",
category: "widget"
},
{
name: "Bar",
category: "fidget"
},
]
etc, where both the name and category have duplicates. What I want to end up with is essentially a list of objects (this is to meet the interface for a 3rd party library), where each object represents a name, and then for each category there is a property that is either true or false, depending on the original list. So for the example the output would be:
const output = [
{
name: "Foo",
widget: true,
fidget: false
},
{
{
name: "Bar",
widget: true,
fidget: true
},
]
I would first go through and make an object of your categories with the categories as keys and default values as false.
Then you can assign this to each object and set the correct keys to true as you go through.
const drawings = [{name: "Foo",category: "widget"},{name: "Bar",category: "widget"},{name: "Bar",category: "fidget"},]
// make category object where everything is false
let category_obj = drawings.reduce((a, item) => (a[item.category] = false, a), {})
let output = drawings.reduce((a, {name, category}) => {
// assign cat
if (!a.hasOwnProperty(name)) a[name] = Object.assign({}, {name}, category_obj)
// set to true if the correct category
a[name][category] = true
return a
}, {})
// the above makes an object, but you only want the array of values
console.log(Object.values(output))
If you already know the categories or if you have infered them as you suggested, you could use Array.reduce() like such:
drawings.reduce(function(acc, curr) {
if (!acc.some(elt => elt.name === curr.name)) {
acc.push({name: curr.name, widget: false, fidget: false})
}
const i = acc.findIndex(elt => elt.name === curr.name)
acc[i][curr.category] = true
return acc
}, [])