Create new object from existing object with new values Angular / Ionic 3 - javascript

I am working on an Ionic 3 project,which uses Angular.
I have a JSON object like below called person. However, I have a Ionic toggle button which enables
various sections based on whats returned from person.
person = { name: "peter", job: "programmer", home: "somewhere"};
person_checked_values = {}
In order to update my toggles I need to pass a boolean. The keys are the same. How can I dynamically build a new object off of
whats returned from person KEYs, but set the value as true so person_checked_values results like below?
person_checked_values = { name: true, job: true, home: true};
I tried to foreach loop person and create a new object from that, but keep getting undefined and stumped. FWIW - I am using _lodash as well so if there is possibly someway to use help from that library its available.

You can use Object.keys to get all of the keys. You can then combine that with the .reduce function of arrays to build an object.
let person = {
name: "peter",
job: "programmer",
home: "somewhere"
};
let result = Object.keys(person).reduce((obj, key) => {
obj[key] = true;
return obj;
}, {})
console.log(result);

Related

Javascript overwrite part of a nested object with object merging

I'm working on a JS project where I need to override some values in my object which contains nested objects.
I'd normally use the following:
const merged = { ...application, ...customer }
So that any data inside of customer can override the application.
However, in my example, customer is overriding the entire applicant nested object and I just need to override the name within that object?
I've put together a JS fiddle which can be found here, what am I missing?
const customer = {
applicant: {
first_name: 'john'
}
}
const application = {
applicant: {
first_name: 'edward',
age: 50
},
income: {
salary: 500
}
}
const merged = { ...application, ...customer }
console.log(merged)
In merged I expect the first_name to be "John" whilst everything else remains in tact.
The properties you want to replace via spreading have to be at the top level of the object. In this case you take the top-level properties of application, which are applicant and income, and then replace the applicant property with that from customer. If you want the name to be replaced you would need something like
const merged = {
...application,
applicant: {...application.applicant, ...customer.applicant}
};
You can do this easily with lodash
const merged = _.merge(customer, application)
https://lodash.com/docs/4.17.15#merge

How to get the name and props of global Objects in Javascript

I understand that variable names are not intrinsic properties of an object and thus cannot be retrieved when passed through functions. But here is my use-case and I'd like to create a mapping between members of UniversityEnums and displayStrings to get the display string.
const UniversityEnums = {
studentStatus: {Enrolled: 'Enrolled', OnHold: 'OnHold', Expelled: 'Expelled'},
professorStatus: {FullTime: 'FullTime', PartTime: 'PartTime', Emeritus: 'Emeritus', Expelled: 'Expelled'}
};
and
const displayStrings = {
studentStatus_Enrolled: 'Student is enrolled in the program',
studentStatus_OnHold: 'Student decided not to participate',
studentStatus_Expelled: 'Student was expelled',
professorStatus_FullTime: 'Staff member is hired fulltime',
professorStatus_PartTime: 'Staff member is hired parttime',
professorStatus_Emeritus: 'Staff member is retired',
professorStatus_Expelled: 'Staff member was expelled'};
My goal is to write a function that grabs a member of UniversityEnums and returns the corresponding display string, for example:
const expelledStudentDispStr = getDispString(UniversityEnums.studentStatus.Expelled);
console.log(expelledStudentDispStr);
// Student was expelled
The code I currently have has two input arguments and is like const expelledStudentDispStr = getDispString('studentStatus', UniversityEnums.studentStatus.Expelled); which needs the name of the enum to get the value but I am looking for an even smarter way!
Thanks in advance.
Note: that I can manipulate the enum object (for example define it with different variable names (or maybe, maybe, append other properties to it or its children). However, I CANNOT change their values because those values are used to compare those statuses against other variables. Also, the displayStrings is coming from a third party source and modifying them for me is not doable (at least easily!)
Possible workaround:
One way that comes to my mind is to modify my enum object to have names that match displayStrings keys:
const UniversityEnums = {
studentStatus: {
studentStatus_Enrolled: 'Enrolled',
studentStatus_OnHold: 'OnHold',
studentStatus_Expelled: 'Expelled'},
professorStatus: {
professorStatus_FullTime: 'FullTime',
professorStatus_PartTime: 'PartTime',
professorStatus_Emeritus: 'Emeritus',
professorStatus_Expelled: 'Expelled'}
};
Your
getDispString(UniversityEnums.studentStatus.Expelled)
is the same as
getDispString("Expelled")
and it would still be the same with your new object as
getDispString(UniversityEnums.studentStatus.studentStatus_Expelled)
you don't give it more information, on the other hand you could transform your enum like that
const UniversityEnums = {
studentStatus: {
Enrolled: {
status: 'Enrolled',
entity: 'student'
},
OnHold: {
status: 'OnHold',
entity: 'student'
},
Expelled: {
status: 'Expelled',
entity: 'student'
}
}
};
so you would give the extra information you need
you could do something like
for (const kind in UniversityEnums)
for (const value in UniversityEnums[kind])
UniversityEnums[kind][value] = {
kind: kind,
value: value
}
from Bergi's answer
Note that I can manipulate the enum object
In that case, it's easy: just put unique values in the enums so that you can distinguish them properly. For example,
for (const kind in UniversityEnums)
for (const value in UniversityEnums[kind])
UniversityEnums[kind][value] = kind + '_' + value;
With that you can write
function getDispString(enumValue) {
return displayStrings[enumValue];
}

How to filter object and updated what is filtered? JavaScript

I want to filter object and update what is filtered as a result.
E.g:
// global object (parent)
let globalObj = {
id: 123,
name: "No Name",
attributes: [{
keyA: "Key",
keyB: "Keys 2",
}]
}
I have the above global parent object, which is the task to accept data and save it. (Like the store in Redux)
let updatedObj = {
id: 123,
name: "New Name",
attributes: [{
keyA: "New Key",
}]
}
Well, now i want copare filter global object with new, filter it and update only what is changed, other must be untached..
As a result I want to get someting like this :
// global object (parent after update)
let globalObj = {
id: 123,
name: "New Name",
attributes: [{
keyA: "New Key",
keyB: "Keys 2",
}]
}
How I can do this?
Thanks!
The easiest way would be to use a deep merge package for this.
You can use deepmerge or lodash merge
If you know exactly what keys you want to update you could simply use Object.assign for each individual level and key. Object.assign does a shallow copy/merge.
For the first level, you can use Object.assign
let mergedObject = Object.assign({}, globalObj, updatedObj)
This will correctly merge top level keys, but attributes will be wrong. So you need to go one level down for this.
merged.attributes = globalObj.attributes.map( (item, index) =>
Object.assign({}, item, updatedObj.attributes[i])
)
This will only work if the arrays have the same size. This is extremely important.
It is not straight forward what merging 2 arrays means. There are a lot of questions that make array merging non trivial:
how to do you add a new item
how do you identify matching elements, so you know what element to update
do you make this decision based on index (like I did), or do you use another strategy
This relies heavily on how you uniquely identify an array element, and this in itself is non trivial.

How to update only one specific property of nested object in associative array

I have associative array.
It's a key(number) and value(object).
I need to keep state of this array same as it is I just need to update one object property.
Example of array:
5678: {OrderId: 1, Title: "Example 1", Users: [{UserId: 1}, {UserId: 2}, {UserId: 3}]}
5679: {OrderId: 2, Title: "Example 2", Users: [{UserId: 1}, {UserId: 2}, {UserId: 3}]}
I need to update Users array property.
I tried this but it doesn't work:
ordersAssociativeArray: {
...state.ordersAssociativeArray,
[action.key]: {
...state.ordersAssociativeArray[action.key],
Users: action.updatedUsers
}
}
This is data inside reducer.
What I did wrong how to fix this?
Something that might help.
When I inspect values in chrome I check previous value and value after execution of my code above:
Before:
ordersAssociativeArray:Array(22) > 5678: Order {OrderId: ...}
After:
ordersAssociativeArray: > 5678: {OrderId: ...}
Solution (code in my reducer)
let temp = Object.assign([], state.ordersAssociativeArray);
temp[action.key].Users = action.updatedUsers;
return {
...state,
ordersAssociativeArray: temp
}
So this code is working fine.
But I still don't understand why? So I have solution but would like if someone can explain me why this way is working and first not?
If it could help here how I put objects in this associative array initialy:
ordersAssociativeArray[someID] = someObject // this object is created by 'new Order(par1, par2 etc.)'
What you are doing is correct, as demonstrated by this fiddle. There may be problem somewhere else in your code.
Something that I would recommend for you is to separate your reducer into two functions, ordersReducer and orderReducer. This way you will avoid the excessive use of dots, which may be what caused you to doubt the correctness of your code.
For example, something like:
const ordersReducer = (state, action) => {
const order = state[action.key]
return {
...state,
[action.key]: orderReducer(order, action)
}
}
const orderReducer = (state, action) => {
return {
...state,
Users: action.updatedUsers
}
}
I hope you find your bug!
Update
In your solution you use let temp = Object.assign([], state.ordersAssociativeArray);. This is fine, but I thought you should know that it is sometimes preferable to use a {} even when you are indexing by numbers.
Arrays in javascript aren't great for representing normalized data, because if an id is missing the js array will still have an undefined entry at that index. For example,
const orders = []
array[5000] = 1 // now my array has 4999 undefined entries
If you use an object with integer keys, on the other hand, you get nice tightly packed entries.
const orders = {}
orders[5000] = 1 // { 5000: 1 } no undefined entries
Here is an article about normalizing state shape in redux. Notice how they migrate from using an array in the original example, to an object with keys like users1.
The problem can be that you're using array in the state but in the reducer you're putting as object. Try doing:
ordersAssociativeArray: [ //an array and not an object
...state.ordersAssociativeArray,
[action.key]: {
...state.ordersAssociativeArray[action.key],
Users: action.updatedUsers
}
]
It will put ordersAssociative array in your state and not an object.

React merge immutable array of objects using React Immutability helpers or Immutable js

I am trying to merge an immutable array of objects using Reacts Immutability helpers or Immutable js which ever one. I am trying to create a list of only records where the names have changed. I am trying to avoid creating duplicates in the list if the name has been changed multiple times before submission which lead me to believe a merge was the path I needed to take. An example of what I am trying to achieve is below.
var objArray = [{id:4, name:'bar'}, {id:10, name:'test'}];
var newObj = {id:4, name:'foo'};
var updatedEntries = update(this.state.nameChanges, {$merge: {newObj});
The Result I am looking for is:
objArray = [{id:4, name:'foo'}, {id:10, name:'test'}]
The Result I seem to be getting is:
objArray = [{id:4, name:'foo'}]
I have tried using Facebook React immutability helpers but cannot seem to get the result I need. I seem to be having a little trouble trying wrapping my head around what the merge function is actually doing. Any help is appreciated.
Thanks
You're almost there, what you need to do is to first filter out the object you want and then using merge via its index in the objArray. The official docs shows how to do this
var objArray = [{id: 4, name: 'bar'}, {id: 10, name: 'test'}];
var i = -1;
objArray.map(function (obj, index) {
if (obj.name === 'bar') i = index;
});
var mergeObject = {};
mergeObject[i] = {$merge: {name: 'Foo'}};
var newState = update(objArray, mergeObject);
>> [[object Object] {
id: 4,
name: "Foo"
}, [object Object] {
id: 10,
name: "test"
}]

Categories