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];
}
Related
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
This question already has answers here:
Find object by id in an array of JavaScript objects
(36 answers)
Closed 2 years ago.
I have a file with 1000s of json rows like below. Im having difficulties locating a specific key in the array.
example json:
{"connection":"98374"
,"db":"8",
,"timestamp":"159905411631"
,"event":"DataCatch"
,"data":[{"key":"ruleid","value":"111"}
,{"key":"responseid","value":"155-response-4"}
,{"key":"responsetype","value":"Capture"}
,{"key":"reason","value":"ClientVisit"}
,{"key":"subreason","value":""}
,{"key":"score","value":"0.00"}
,{"key":"comment","value":""}]
}
I need to be able to find the "reason" key in the "data" array and replace the "value" with "test". The "data" array doesn't always appear on every json row, only when the "event" "dataCatch" is present.
I can parse it into a variable but I can only call the "data" array as a whole. Any ideas how to target specific values in an array?
Having a little trouble with this in Typescript.
There are any number of ways to go about this, but here's one.
First, parse your JSON into an array of objects.
Each element of the array will then look something like this:
{
connection: '98374',
db: '8',
timestamp: '159905411631'
event: 'DataCatch',
data: [
{ key: 'ruleid', value: '111' },
{ key: 'responseid', value: '155-response-4' },
{ key: 'responsetype', value: 'Capture' },
{ key: 'reason', value: 'ClientVisit' },
{ key: 'subreason', value: '' },
{ key: 'score', value: '0.00' },
{ key: 'comment', value: '' },
],
}
Let's call our array of objects allData, so we can refer to it later.
Now we can begin our "surgery".
We'll work from the inside-out, first looking at what needs to be done to a specific entry in an element's data array.
Here's a function that will do just what we need:
function updateReason(entry) {
if (entry.key === 'reason') {
return { ...entry, value: 'test' };
} else {
return entry;
}
}
This function checks if the provided entry has a key with a value of 'reason', and -- if so -- returns a new entry that is identical to the provided one except its value is 'test'.
How can we use this to update an entire data array (in an entry that has data, that is)?
We simply delegate the work to our dear friend map:
function updateData(data) {
// or simply `data.map(updateEntry);`
return data.map(entry => updateEntry(entry));
}
We're slowly working our way "outwards".
What about updating an entire entry in our big allData array (which may or may not contain data)?
// I've called such an entry a "collection", because I already used the name
// "entry" above :(
// A "collection" is just an entry in the big `allData` array.
function updateCollection(collection) {
if (collection.event === 'DataCatch') {
return {
...collection, // Leave everything else the way it is
data: updateData(collection.data), // But update the `data` array
};
} else {
return collection;
}
}
So close.
The last thing we need to do is apply this transformation to every element of our parsed allData array:
// or `allData.map(updateCollection);`
const updatedData = allData.map(collection => updateCollection(collection));
Also:
Q: Wouldn't it be cheaper to mutate the entry?
A: It would be cheaper, but not that much cheaper, due to a large amount of "structural sharing" that occurs here. I would recommend this approach unless you either need to mutate your input for some reason, or performance requirements demand it.
You need to map over the data key in your data variable like this.
data.data = data.data.map((item) => {
if (item.key === "reason") {
item.value = "test";
}
return item;
});
the data key is an array of values, so you need to loop through it and compare the value of the key property to the value you are looking for, if it matches then you can update the value property
https://codesandbox.io/s/angry-shirley-1gh83?file=/src/index.ts:666-782
Given the object:
const product = {
food: true,
clothes: false
}
is there a way to programmatically get the name of some key without using Object.keys or similar methods. Something like product.food.getKeyName() which would return a string 'food'. I find that I often have to add object key names to some constants object like:
const products = {
food: 'food',
clothes: 'clothes'
}
which is my primary motivation to figure out a programmatic solution.
Here's an example use case. I want to run over all keys of an object and have different behavior for each key:
Object.keys(product).map(key => {
if (key === 'food') {
// do something specific for food
}
})
but I don't want to write string literals like 'food'.
Thanks to #Enijar's tip indeed it is possible to programmatically retrieve object keys names using Javascript Proxy API as follows:
const product = {
food: true,
clothes: false
}
const proxy = new Proxy(product, {
get: function(originalObject, objectKey) {
if (originalObject.hasOwnProperty(objectKey)) {
return objectKey
}
throw new Error(`The field '${objectKey}' doesn't exist.`)
},
})
console.log(proxy.food) // logs 'food'
console.log(product.food) // logs 'true'
I've looked in stack, but I couldn't find the answer to my question, if It's a duplicate I'm really sorry.
I have an array of objects:
export const people = [
{
id: 1,
name: "Thom"
},
{
id: 2,
name: "Bob"
}
];
I am importing this file:
import {people} from '../Person';
I'm assigning the state:
state = {
peopleData: people
}
And I'm trying to destruct this array like this, but unfortunately, I'm not allowed to do that:
const{people} = this.state.peopleData;
What is the reason that I'm not able to iterate with map function over my people?
{people.map(person=> (<Person key={person.id} personInfo={person}/>))}
I can do like that of course, but I don't want to, because If I would need to iterate couple more times I would need always to write the same code this.state.peopleData...:
{
this.state.peopleData.map(person=> (<Person key={person.id} personInfo={person}/>
))}
I'm assigning the state:
state = {
peopleData: people
}
And I'm trying to destruct this array like this, but unfortunately, I'm not allowed to do that:
const{people} = this.state.peopleData;
It would be either this, without destructuring:
const people = this.state.peopleData;
or this with destructuring:
const {peopleData: people} = this.state;
...which says "take the value of the property peopleData from this.state and put it into the constant people.
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);