Clean way to reassign an object in es6 with conditionality - javascript

I'm new to ES6 and I can't find a cleaner way to make this code.
Can I get the child object if it exists or create it otherwise? To remove these ifs.
if (object?.tabs?.data) {
object = {
...object,
tabs: {
...object?.tabs,
data: {
...object?.tabs?.data,
id: newId,
},
},
};
} else if (object?.tabs) {
object = {
...object,
tabs: {
...object?.tabs,
data: {
id: newId,
},
},
};
} else {
object = {
...object,
tabs: {
data: {
id: newId,
},
},
};
}

this can be a cleaner way:
let newId = 1;
let object = {
tabs: {
data1: {
id: 2
}
}
};
let o = (object = object ?? {});
for (let [k, v] of Object.entries({
tabs: object?.tabs,
data: object?.tabs?.data ?? {id: newId}
}))
o = (o[k] = v ?? {});
console.log(object)

Related

JavaScript Array attribute change

I have an array like this.
let arr = [
{
"ABBRIVATION":"ISB",
"name":"ISLAMABAD",
},
{
"ABBRIVATION":"RAW",
"name":"PINDI",
},
{
"ABBRIVATION":"SWB",
"name":"SWABI",
},
{
"ABBRIVATION":"AQ",
"name":"AQEEL",
},
]
I want to change it to like this
let me explain it a little. I want to assign the abbreviation directly to the name and the iterate through that array
let outout = [
{
"ISB":"ISLAMABAD"
},
{
"RAW":"ISLAMABAD"
},
{
"SWB":"SWABI"
},
{
"AQ":"AQEEL"
},
]
that is what I tried
let k = arr.map((item) => {
return item.ABB = item.name
})
console.log(k)
and here is the output
[ 'ISLAMABAD', 'PINDI', 'SWABI', 'AQEEL' ]
Here you go, use array map, simples
let arr = [
{
"ABBRIVATION":"ISB",
"name":"ISLAMABAD",
},
{
"ABBRIVATION":"RAW",
"name":"PINDI",
},
{
"ABBRIVATION":"SWB",
"name":"SWABI",
},
{
"ABBRIVATION":"AQ",
"name":"AQEEL",
},
]
let outout = arr.map(({ABBRIVATION, name}) => ({[ABBRIVATION]: name}));
console.log(outout);
Nothing more than a simple Array.prototype.map() needed.
let arr = [
{
ABBRIVATION: "ISB",
name: "ISLAMABAD",
},
{
ABBRIVATION: "RAW",
name: "PINDI",
},
{
ABBRIVATION: "SWB",
name: "SWABI",
},
{
ABBRIVATION: "AQ",
name: "AQEEL",
},
];
const result = arr.map(e => ({ [e.ABBRIVATION]: e.name }));
console.log(result);
map over the array of objects (map returns a new array) and assign the name to a new key defined by the abbreviation.
You code works the way it does because item.ABB is undefined, but you're also assigning item.name to it which does get returned, so you just get an array of names returned.
const arr=[{ABBRIVATION:"ISB",name:"ISLAMABAD"},{ABBRIVATION:"RAW",name:"PINDI"},{ABBRIVATION:"SWB",name:"SWABI"},{ABBRIVATION:"AQ",name:"AQEEL"}];
const out = arr.map(obj => {
return { [obj.ABBRIVATION]: obj.name };
});
console.log(out);
Hi I have seen people answer, but most of them use the map function, I provide some other solutions, hoping to expand the thinking
Use forEach function
const datas = [
{
"ABBRIVATION":"ISB",
"name":"ISLAMABAD",
},
{
"ABBRIVATION":"RAW",
"name":"PINDI",
},
{
"ABBRIVATION":"SWB",
"name":"SWABI",
},
{
"ABBRIVATION":"AQ",
"name":"AQEEL",
}
];
datas.forEach((obj, i, arr) => {
const{'ABBRIVATION':k, 'name':v} = obj;
arr[i] = {[k]:v};
});
console.log(datas);
Use flatMap function
const datas = [
{
"ABBRIVATION":"ISB",
"name":"ISLAMABAD",
},
{
"ABBRIVATION":"RAW",
"name":"PINDI",
},
{
"ABBRIVATION":"SWB",
"name":"SWABI",
},
{
"ABBRIVATION":"AQ",
"name":"AQEEL",
}
];
const result = datas.flatMap(obj => {
const {'ABBRIVATION':k, 'name':v} = obj;
return {[k]:v};
});
console.log(result);
this is how you suppose to do it.
arr.reduce((d, c)=>([...d, {[c.ABBRIVATION]: c.name}]),[])
let arr = [
{
"ABBRIVATION":"ISB",
"name":"ISLAMABAD",
},
{
"ABBRIVATION":"RAW",
"name":"PINDI",
},
{
"ABBRIVATION":"SWB",
"name":"SWABI",
},
{
"ABBRIVATION":"AQ",
"name":"AQEEL",
},
]
console.log(arr.reduce((data, current)=>([...data, {[current.ABBRIVATION]: current.name}]),[]))

NGRX/REDUX: update value in deep object by json path

I have an object like:
{
categories: {
Professional: {
active: false,
names: [
{
id: 1,
name: "Golf",
active: false
},
{
id: 2,
name: "Ultimate Frisbee",
active: false
}
]
}}
and i want update categories.Professional.active with true, into the reducer i have:
return {
...state,
categories: {
...state.categories,
Professional: {
...state.categories.Professional,
active: true
}
}
}
now i want write a function for spreadfy an object and update a single property by json path. Eg.
return deepPatch(state, 'categories.Professional.active', true);
the goal for the function deepPatch is build at runtime this structure:
return Object.assign({}, obj, {
categories: Object.assign({}, state.categories, {
Professional: Object.assign({}, state.Professional, {
active: true
})
})
});
i have tried but don't know how make a recursive spread:
function deepPatch(obj: any, path: string; value: any){
const arrayPath: string[] = path.split('.');
const currObj = null;
for (let i = 0, e = arrayPath.length; i < e; i++) {
const currPath = arrayPath[i];
currObj = obj[currPath];
currObj = Object.assign({}, currObj, ???);
}
return currObj;
}
You could get the first key and create a new object by calling the function again until no more keys are available.
function deepPatch(object, path, value) {
var [key, rest] = path.match(/^[^.]+|[^.].*$/g);
return { ...object, [key]: rest
? deepPatch(object[key], rest, value)
: value
};
}
var state = { categories: { Professional: { active: false, names: [{ id: 1, name: "Golf", active: false }, { id: 2, name: "Ultimate Frisbee", active: false }] } } },
result = deepPatch(state, 'categories.Professional.active', true);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
const deepSet = function (object, path, value) {
if (typeof path === 'string') {
path = path.split('.');
}
if (path.length > 1) {
const e = path.shift();
deepSet(object[e] = Object.prototype.toString.call(object[e]) === '[object Object]' ? object[e] : {}, path, value);
} else {
object[path[0]] = value;
}
};
I'm using this function. Works for me.

Appending to an array access by a key in Redux Reducer

I'm trying to add to my state within a reducer. I need to access a key, and then add to an array within that key. This is what my state currently looks like:
{teamMembers: {
PersonId1: [{ object1 }, {object2 }]
PersonId2: [{ object3 }, { object4 }]
PersonId3: [{ object5 }, { object6 }]
}}
I need to access a PersonId, based on what the action inputs, and then append an item from the action to the array. Ideally it would also create a new key and array if the key PersonId didn't already exist.
In your reducer, just do a little data manipulation. Remember to only manipulate a copy of your state and not your actual state.
const action = {
payload: {
personId: 'PersonId4',
item: {}
}
}
const state = {
PersonId1: [{ object1 }, {object2 }]
PersonId2: [{ object3 }, { object4 }]
PersonId3: [{ object5 }, { object6 }]
}
const {personId, item} = action.payload
let newState = {...state}
if (personId in newState) {
newState[personId].push(item)
} else {
newState[personId] = [item]
}
return newState
You can conditionally check for the existence of the key and then add it to an already existing array or create a new one.
Something like this:
const newItems = state[id] ? [...state[id], ...items] : items;
//...
return {
...state,
[id]: newItems
}
Note that i'm using the object spread syntax which is a proposal (in stage 3) and you need the babel plugin babel-plugin-transform-object-rest-spread to support it (or babel stage 3 preset).
Running example:
const initialState = {
teamMembers: {
PersonId1: [{
name: 'object1'
}, {
name: 'object2'
}],
PersonId2: [{
name: 'object3'
}, {
name: 'object4'
}],
PersonId3: [{
name: 'object5'
}, {
name: 'object6'
}]
}
};
const actionOne = {
type: 'ADD',
payload: {
id: 'PersonId2',
items: [{
name: 'object444'
}]
}
}
const actionTwo = {
type: 'ADD',
payload: {
id: 'PersonId777',
items: [{
name: 'object777'
}]
}
}
const reducer = (state = {}, action) => {
switch (action.type) {
case 'ADD':
{
const {
id,
items
} = action.payload;
const newItems = state[id] ? [...state[id], ...items] : items;
return {
...state,
[id]: newItems
}
}
default:
return state;
}
}
const reducerResultOne = reducer(initialState.teamMembers, actionOne);
console.log('reducerResultOne', reducerResultOne);
const reducerResultTwo = reducer(initialState.teamMembers, actionTwo);
console.log('reducerResultTwo', reducerResultTwo);

Filter object containing array of object

I would like to filter my data depending on a typed keyword.
https://jsfiddle.net/LeoCoco/e96L8akn/
let keyword = '-pre';
let data = {
'Basic': [{
name: 'a-basic'
}, {
name: 'b-basic'
}, {
name: 'c-basic'
}],
'Premium': [{
name: 'a-pre'
}, {
name: 'b-pre'
}, {
name: 'c-pre'
}],
'Extra': [{
name: 'a-ext'
}, {
name: 'b-ext'
}, {
name: 'c-ext'
}],
};
Output
'Premium': [{name: 'a-pre'}, { name: 'b-pre'}, { name: 'c-pre'}]
My try
lodash.forEach(data, (card) => {
card = card.filter(o => {
return Object.keys(o).some(k => {
return typeof o[k] === 'string' && o[k].toLowerCase().includes(keyword.toLowerCase());
});
});
})
But it does not work.The difficulty for me is that the filtering must happen on the nested object keys contained in each array.
var result={};
Object.keys(data).forEach(key => {
result[key] = data[key].filter(o => {
return Object.keys(o).some(k =>typeof o[k] === 'string' && o[k].toLowerCase().includes(keyword.toLowerCase()));
});
})
Because this is object you can use reduce() on Object.keys() instead and then inside use every() to check for keyword.
let keyword = '-pre';
let data = {"Basic":[{"name":"a-basic"},{"name":"b-basic"},{"name":"c-basic"}],"Premium":[{"name":"a-pre"},{"name":"b-pre"},{"name":"c-pre"}],"Extra":[{"name":"a-ext"},{"name":"b-ext"},{"name":"c-ext"}]}
var result = Object.keys(data).reduce(function(r, e) {
var check = data[e].every(o => o.name.indexOf(keyword) != -1);
if(check) r[e] = data[e]
return r;
}, {})
console.log(result)

Filter a dom object of input tags

I am building an object from a form that is currently rendered server side. I collect all the check boxes displayed in the image below and I am trying to sort them in a way that all the check boxes under each step (1, 2, 3 etc) is a single object based on the property parentNode.
Currently the document.querySelectorAll('.checkboxes') fetches all the checkboxes in following format.
var newObj = [
{
name: 'one',
parentNode: {
id: 'stepOne'
}
},
{
name: 'two',
parentNode: {
id: 'stepTwo'
}
},
{
name: 'three',
parentNode: {
id: 'stepOne'
}
},
]
The new object should be:
var newObj = {
stepOne: [
{
name: 'one',
parentNode: {
id: 'stepOne'
}
},
{
name: 'three',
parentNode: {
id: 'stepOne'
}
},
],
stepTwo: [
{
name: 'two',
parentNode: {
id: 'stepTwo'
}
},
]
}
Usually I do something like this:
let stepOne = function(step) {
return step.parentNode.getAttribute('id') === 'stepOne';
}
let stepTwo = function(step) {
return step.parentNode.getAttribute('id') === 'stepTwo';
}
let allTheStepOnes = fetchCheckBoxes.filter(stepOne);
But filter doesn't work on dom object and this seems inefficient as well.
Proper way of doing this is a forEach loop and using associative arrays like this:
let newObject = {};
originalObject.forEach((item)=>{
let step = item.parentNode.id
if (newObj[step] === undefined) {
newObj[step] = []
}
newObj[step].push(item)
})
Using reduce we can reduce your current array into the new structure.
return newObj.reduce(function(acc, item) {
If acc[item.parentNode.id] has been defined before, retrieve this. Otherwise set it to an empty array:
acc[item.parentNode.id] = (acc[item.parentNode.id] || [])
Add the item to the array and then return it:
acc[item.parentNode.id].push(item);
return acc;
We set the accumulator as {} to start with.
Snippet to show the workings.
var newObj = [{
name: 'one',
parentNode: {
id: 'stepOne'
}
}, {
name: 'two',
parentNode: {
id: 'stepTwo'
}
}, {
name: 'three',
parentNode: {
id: 'stepOne'
}
}, ];
var newOrder = function(prevList) {
return prevList.reduce(function(acc, item) {
acc[item.parentNode.id] = (acc[item.parentNode.id] || [])
acc[item.parentNode.id].push(item);
return acc;
}, {});
}
console.log(newOrder(newObj));
This function should do the trick
function mapObj(obj) {
var result = {};
for(var i = 0; i < obj.length; i++) {
var e = obj[i];
result[e.parentNode.id] = result[e.parentNode.id] || [];
result[e.parentNode.id].push(e);
}
return result;
}

Categories

Resources