How to destructure nested objects in for-loop - javascript

var users = [
{ user: "Name1",geo:{lat:'12',long:'13'} },
{ user: "Name2",geo:{lat:'12',long:'13'}, age: 2 },
{ user: "Name2",geo:{lat:'12',long:'13'} },
{ user: "Name3",geo:{lat:'12',long:'13'}, age: 4 }
];
Above is the array of objects.
Here is the for-loop I destructured and get user and age but I want lat and long also how will I do that ? I want it through destructuring and for-loop like I did with user and age
for (let { user, age = "DEFAULT AGE" } of users) {
console.log(user, age);
}

You can use this:
for (let {user, age = "DEFAULT AGE", geo: {lat, long}} of users) {
console.log(user, age, lat, long);
}
You have already successfully destructured user (simply by the property name in the object) and age (with a default value as well).
To use nested destructuring, step by step, simply put the property name geo in there as well, since that’s the next property on the objects you’re iterating over that contains your needed values:
{user, age = "DEFAULT AGE", geo} — this would yield {lat: "12", long: "13"} for geo.
To access the nested properties directly, follow the object structure:
{user, age = "DEFAULT AGE", geo: {}} — this would just validate that geo is indeed an object.
Then, list the properties you want to access in that object:
{user, age = "DEFAULT AGE", geo: {lat, long}} — this would yield "12" for lat and "13" for long.
You could even go a step further and rename those properties:
{user, age = "DEFAULT AGE", geo: {lat: latitude, long: longitude}} — this would yield "12" for latitude and "13" for longitude.
These are the basic cases for destructuring objects:
name means “just assign the entire value to name”.
{} means “check that the value to be destructured is an object or can be converted into one, i.e. is neither null nor undefined; create no variables”.
{ prop } means “get the value of prop as the variable prop”.
{ prop: rename } means “follow the prop property and get its value as the variable rename”1.
{ prop = value } means “get the value of prop as the variable prop, but assign value if prop yields undefined”2.
For the “rename” case, the rules apply recursively: rename is like name, so it can be replaced by {}, or { anotherProp }, or { anotherProp: anotherRename }, or { anotherProp = anotherDefault }, etc.
Other properties on the same object level may be added via commas, like {propA, propB}.
For arrays, similar cases exist: [] would validate that the value to be destructured is an iterable object; [a, b] has the same meaning as {0: a, 1: b}; etc.
1: Note that in the case of { prop: something } no variable prop is created.
2: “yields undefined” means that obj.prop would be equal to undefined which means either that the property exists and has the literal value undefined or that the property doesn’t exist.

If you're just trying to find a given user and return the geo for it, this will do:
users.find( u => u.user === 'Name1' ).geo;
Keep in mind, you would want to do some checks aginst your 'find result' before trying to use it. For example:
const user = users.find( u => u.user === 'Name1' );
if (user && user.hasOwnProperty('geo')) {
console.log(user.geo);
}

Related

How to dynamically update an object field in JavaScript/TypeScript

I have a method for handling an update on this object. In this method I want to accept any field value that the object has, such as name, age, weight, eyeColor etc. If that field exists within that object, I'd like to be able to update the object dynamically for any field they pass in.
I am currently doing it incorrectly I believe with the spread operator while trying to update one field in the object. There is an error that fieldName does not exist within myObject. Does anyone know how to do this dynamically without need for a long switch statement checking each of the fields against fieldName passed in? In previous attempts tweaking with this I have successfully added a new field to the object named "fieldName" which is also not what I wanted.
If anyone has any ideas, that would be so helpful, thank you!
let myObject = {
name: 'John',
lastName: 'Smith',
age: 26,
weight: 200,
eyeColor: 'blue',
hairColor: 'blonde'
};
const handleUpdate = (fieldName: string, fieldValue: string | number) => {
if (fieldName in myObject) {
myObject = {...myObject, fieldName: fieldValue};
}
}
handleUpdate('name', 'Jack'); // Want this call to update the name of 'John' to 'Jack'
In short, you're looking for:
{...myObject, [fieldName]: fieldValue}
You can make a generalized, typesafe function to do this as follows:
function updateProp<TObj, K extends keyof TObj>(obj: TObj, key: K, value: TObj[K]) {
return {...obj, [key]: value};
}
and call it as follows:
const foo = { a: 1, b: "monkey" };
const updatedFoo = updateProp(foo, "b", "hello world")
Playground Link
You're looking for the Bracket notation property accessor:
myObject[fieldName] = fieldValue
Compared to the approach with the spread operator, this does actually update the object in place. I.e. if the reference in myObject was previously copied elsewhere, that reference will also "see" the updated field.
Whereas, by overriding the value with myObject = {...myObject}, you're creating a new object each time.

how to transform value string in object to new const js

i need to convert a object with have key value to new object that contain new const named form platform and have name to value in js how to do it?
posters: [
{ platform: facebook; name: ["user test1","user test2"] },
{ platform: instagram; name: ["Ig test1","Ig test2"] },
]
in to
posters: {
facebook: ["user test1","user test2"] ,
instagram: ["Ig test1","Ig test2"] ,
}
Your input array is invalid. There are no strings around your platform values, and you're separating your object properties with a semi-colon rather than a comma. So you would need to fix that in order to proceed.
It looks as if posters is a property within a larger object so this answer will take that into account.
Use reduce on the posters array to iterate over the objects in the array and return an object where the keys are the platform names, and the values the name arrays.
Since it looks like posters is within a larger object we'll rebuild the object using the spread syntax.
const data={posters:[{platform:"facebook",name:["user test1","user test2"]},{platform:"instagram",name:["Ig test1","Ig test2"]}]};
// Create a new object
const updated = {
// Spread out the old object into it
...data,
// And replace the old `posters` property with an
// object using `reduce`. Destructure the `platform`
// and `name` properties from the object, and then
// use them to add a key and a value to the initial
// object (`acc`/accumulator)
posters: data.posters.reduce((acc, obj) => {
const { platform, name } = obj;
acc[platform] = name;
return acc;
}, {})
};
console.log(updated);
Additional documentation
Destructuring assignment
const postersArray = [
{ platform: facebook, name: ["user test1","user test2"] },
{ platform: instagram, name: ["Ig test1","Ig test2"] }
]
const postersObject = postersArray.reduce((previous, current) => {
return {
…previous,
[current.platform]: current.name
}
},{})

How to Set a Javascript Object Key to Be Another Object's Value

I have an Javascript object called person with various properties such as id, name, phone, etc.
I want to create a new Javascript object called roster that is just the name. Something like this:
let person = { name: "Hilda", "id": 123, "phone": 000-000-0000 };
let roster = { person.name : person.phone };
However, React throws an error having person.name in the key. It doesn't matter if I do person.name or person["name"]. I have to do:
let roster = {};
roster[person.name] = person.phone;
Is there some special syntax to allow person.name to be set as the key directly, or is the work-around required?
Use []
let person = { name: "Hilda", "id": 123, "phone": "000-000-0000" };
let roster = { [person.name] : person.phone };
console.log(roster)
Vugar's answer is correct, this can be done by placing brackets [] around the first object's property name.
This is called a computed property name. From the MDN web docs:
The object initializer syntax also supports computed property names.
That allows you to put an expression in brackets [], that will be
computed and used as the property name. This is reminiscent of the
bracket notation of the property accessor syntax, which you may have
used to read and set properties already.
Now you can use a similar syntax in object literals, too:
// Computed property names
let i = 0;
const a = {
[`foo${++i}`]: i,
[`foo${++i}`]: i,
[`foo${++i}`]: i,
};
console.log(a.foo1); // 1
console.log(a.foo2); // 2
console.log(a.foo3); // 3
const items = ["A", "B", "C"];
const obj = {
[items]: "Hello",
};
console.log(obj); // A,B,C: "Hello"
console.log(obj["A,B,C"]); // "Hello"
const param = 'size';
const config = {
[param]: 12,
[`mobile${param.charAt(0).toUpperCase()}${param.slice(1)}`]: 4,
};
console.log(config); // {size: 12, mobileSize: 4}
MDN Docs Reference

Iterating through a an array executing a switch statement returns TypeError: Cannot assign to read only property 'location' of object '#<Object>'

I have a read only array that i copied to become a mutable array let mutableForecast = [...forecast] I am taking that new array and iterating through it with forEach so i can mutate the array. im trying to use some flow control with a switch statement, but I am getting TypeError: Cannot assign to read only property 'location' of object '#<Object>'
let mutableForecast = [...forecast]
mutableForecast.forEach((obj, i) => {
switch (obj.location) {
case obj.location === "BRITISH_COLUMBIA":
obj.location = "BC"
break;
default:
obj.location = "oother"
}
})
Whats the issue here? I've look at this, this, this and some others but cannot find an answer.
This is what the forecast array looks like before i copied it
It's hard to be sure without knowing where forecast comes from, but I suspect the problem is that the elements of the array are not plain objects, but instances of a custom type that are defined as immutable. Your third link has the likely solution. The key is that you can't convert an array of immutables into an array of mutables simply by using rest & spread in this way. You need to modify the mutability of each item in the array individually.
You probably need something like this:
let mutableForecast = [...forecast]
mutableForecast.forEach((obj, i) => {
// make this element's location property mutable
Object.defineProperty(obj, 'location', { writable: true })
// calculate and set new value
switch (obj.location) {
case 'BRITISH_COLUMBIA':
obj.location = 'BC'
break;
default:
obj.location = 'other'
}
})
This might also work, and I think it's cleaner. You'd have to try it to be sure:
let mutableForecast = Array.from(forecast)
.map(forecastItem => ({
...forecastItem,
location: getShortLocation(forecastItem.location)
}))
function getShortLocation( sourceLocation ) {
switch (sourceLocation) {
case 'BRITISH_COLUMBIA': return 'BC'
default: return 'other'
}
}
The core problem we're working around is that whatever package gives you forecast, it clearly trafficks in some custom datatype, some of whose properties are defined as immutable. That fact doesn't show up when you log the objects, and it isn't changed when you convert an array-like container into an array.
That's because [...forecast] doesn't edit the items, it just copies them as-is from one data structure into another. Actually, be to precise, it copies references to those objects into a new array. If the original objects are weird things with locked properties, then your new array will consist of weird things with locked properties. If we want to change the value of that property on each element, we need to redefine the property before doing so.
Consider a case like this:
let myDog = {
species: 'dog',
name: 'Fido'
}
//> myDog { species: 'dog', name: 'Fido' }
We can create another object with the same properties like so:
let congruentAnimal = {
...myDog
}
//> congruentAnimal { species: 'dog', name: 'Fido' }
If the same property names occurs twice, the engine will only honor the last one:
let myDog = {
species: 'cat',
name: 'Fido',
species: 'dog' // this will cause cat to be ignored
}
//> myDog { name: 'Fido', species: 'dog' }
So, we can override individual object properties while copying by re-declaring those properties last:
let anotherCongruentAnimal = {
...myDog,
species: 'NEW DOG'
}
//> anotherCongruentAnimal { name: 'Fido', species: 'NEW DOG' }
That's what is going on in that second snippet. Here's an expanded version:
// create a real array whose elements are *references* to
// the objects in the array-like forecast
let arrayOfImmutableForecasts = Array.from(forecast)
// create another real array of new objects
// whose property names, values, and metadata are
// the same as the source objects
let arrayOfMutableForecasts = arrayOfImmutableForecasts.map(originalObject => {
let newObject = {
// I think this will also preserve special rules like immutability
...originalObject,
// before we finalize the object, we declare a new simple property
// the engine will _drop_ the implied prop declaration from above
// and define the prop based on this simple declaration instead
location: 'new value'
}
return newObject
})
It seems like you are not allowed to mutate the location property of the objects in the array...
You can try creating a clone of the object and mutate that:
let mutableForecast = [...forecast]
mutableForecast = mutableForecast.map(obj => {
const location = obj.location
const objClone = {}
for (const key in obj) {
if (key !== 'location') objClone[key] = obj[key]
}
switch (location) {
case "BRITISH_COLUMBIA":
objClone.location = "BC"
break;
default:
objClone.location = "other"
}
return objClone
})
If that fails, you can try creating a new property insteade, and later read that property:
let mutableForecast = [...forecast]
mutableForecast.forEach((obj, i) => {
switch (obj.location) {
case "BRITISH_COLUMBIA":
obj.newLocation = "BC"
break;
default:
obj.newLocation = "other"
}
})

matching two object by partial match javascript

I have these 2 objects, where I want to alter the value of a 2nd object by checking the value of the 1st object. But I'm stuck, I've prepared a sample below
const inputs = {
"firstname": "james",
"lastname": ""
}
const errors = {
firstname_error: false,
firstname_error_msg: "first name is invalid",
lastname_error: false, //make this true because inputs.lastname is false / empty string
lastname_error_msg: "last name is invalid",
}
Object.entries(inputs).forEach(([key, value]) => {
if(!value) {
//how to make errors.lastname_error to true if inputs.lastname is false empty string?
}
})
Use Square Bracket Notation to assign the value.
An object property name can be any valid JavaScript string, or anything that can be converted to a string, including the empty string. However, any property name that is not a valid JavaScript identifier (for example, a property name that has a space or a hyphen, or that starts with a number) can only be accessed using the square bracket notation. This notation is also very useful when property names are to be dynamically determined (when the property name is not determined until runtime).
Concatenate _error to they key which will target required key in error object.
const inputs = {
"firstname": "james",
"lastname": ""
}
const errors = {
firstname_error: false,
firstname_error_msg: "first name is invalid",
lastname_error: false,
lastname_error_msg: "last name is invalid",
}
Object.entries(inputs).forEach(([key, value]) => {
if (!value) {
errors[`${key}_error`] = true;
}
});
console.log(errors);
If you use Lodash library, refer to isEqual and intersection functions
I get the key value of inputs and in a for cycle i check if exist the relative key with "_error" in errors object and the value ok inputs[key] is not empty.
I use this code and work:
const inputs = {
"firstname": "james",
"lastname": ""
}
const errors = {
firstname_error: false,
firstname_error_msg: "first name is invalid",
lastname_error: false, //make this true because inputs.lastname is false / empty string
lastname_error_msg: "last name is invalid",
}
for (const key in inputs) {
if (errors.hasOwnProperty(`${key}_error`) && !inputs[key]) {
errors[`${key}_error`] = true;
}
}

Categories

Resources