Update object property in javascript? - javascript

const [fields, setFields] = useState({
country: { country: "India" },
address: { street1: "street1", street2: "street2" },
});
This is my object. I want to update an inner property from this object
let id = 'street1'
let params = { ...fields, [id]: value }; //This will add a new prop
But i want to update the street1 inside the address object. How to do that?

Use this:
const updatedObject = {
...fields,
address: {
...fields.address,
[id]: value,
},
};

Try this
{...fields,address:{...fields.address,"street1":"abc"}}

let userAddress = {
country: { country: "India" },
address: { street1: "street1", street2: "street2" },
};
I believe the situation is to update the value of object that is nested , in this case street1.
Best way with ES6 would be to destructure and update the value.
userAddress = {
...userAddress,
address: { ...state.address, street1: newValue },
};

Related

Compare and get difference from two object for patch api request in react js?

i m having two objects previous and new one, i trying to compare and get difference for those objects, send to as patch payload from patch api,
compare each properties in object if any of the property has any difference i want all those difference in new object as payload
How can i achieve this please help me find the solution?
Is there any lodash method for this solution?
let obj = {
Name: "Ajmal",
age: 25,
email: "ajmaln#gmail.com",
contact: [12345678, 987654321],
address: {
houseName: "ABC",
street: "XYZ",
pin: 67891
}
}
let obj2 = {
Name: "Ajmal",
age: 25,
email: "something#gmail.com",
contact: [12345678, 11111111],
address: {
houseName: "ABC",
street: "XYZ",
pin: 111
}
}
result payload i m expecting would look like
let payload = {
email: "something#gmail.com",
contact: [12345678, 11111111],
address: {
pin: 111
}
}
Mista NewbeedRecursion to your service:
const compare = (obj1, obj2) => {
const keys = Object.keys(obj1);
const payload = {};
keys.forEach((el) => {
const first = obj1[el];
const second = obj2[el];
let check;
if (first !== second) {
if (first instanceof Object && !(first instanceof Array))
check = compare(first, second);
payload[el] = check || second;
}
});
return payload;
};
Here is a approach with immer that may guide you to a proper solution
This is not a generic approach but makes things easier by relying on immer
import produce, { applyPatches, enablePatches } from "immer";
import { difference } from "lodash";
// once in your app
enablePatches();
let obj = {
Name: "Ajmal",
age: 25,
email: "ajmaln#gmail.com",
contact: [12345678, 987654321],
address: {
houseName: "ABC",
street: "XYZ",
pin: 67891
}
};
let obj2 = {
Name: "Ajmal",
age: 25,
email: "something#gmail.com",
contact: [12345678, 11111111],
address: {
houseName: "ABC",
street: "XYZ",
pin: 111
}
};
Gettig the patch updates
let fork = { ...obj };
let changes = [];
const updatedItem = produce(
fork,
(draft) => {
// object specific updates
draft.Name = obj2.Name;
draft.age = obj2.age;
draft.email = obj2.email;
draft.address.houseName = obj2.address.houseName;
draft.address.street = obj2.address.street;
draft.address.pin = obj2.address.pin;
const originalContact = original(draft.contact);
const contactDiff = difference(obj2.contact, originalContact);
console.log("diff", contactDiff);
if (contactDiff?.length) {
draft.contact = contactDiff;
}
},
(patches) => {
changes.push(...patches);
}
);
//Problem here => default values need to be given to state
// so the default values need to be excluded from the patch
let state = { contact: [], address: {} };
const patch = applyPatches(state, changes);
console.log("patch", patch);
logs changes op
contact: Array(1)
0: 11111111
address: Object
pin: 111
email: "something#gmail.com"
Hope this helps you in some way
Cheers

How to change nested object attribute using JavaScript spread operator?

I have a JavaScript object like below
const obj = {
name: 'Jone',
location: {
presentAddress: {
livingAddress: {
City: {name: 'New York'},
Country: {name: 'USA'},
}
}
}
}
I'm trying to change city name New York to London
So, I have tried below code
console.log({
...obj,
location:{
...obj.location,
presentAddress:{
...obj.location.presentAddress,
livingAddress: {
...obj.location.presentAddress.livingAddress,
City:{
...obj.location.presentAddress.livingAddress.City,
name: "London"
}
}
}
}
})
It's working fine, My question is has there any shorter way to do this change?
Try setting the nested property directly.
obj.location.presentAddress.livingAddress.City.name = "London"

retrieving data from nested object

I have this object example only:
{
id: 301
payload: {
1: {
house_no: 1234,
city: London
},
2: {
house_no: 0000
city: Paris
}
}
}
I need to extract only the house_no and city for both 1 and 2.
I have tried for loping through like so: *Address passed to the loop is the object above
let item = [];
for(let x in address){
item.push(item[x]);
}
console.log('Address', item.city);
This gives me array with undefined elements:
[
0: undefined
1: undefined
]
Could you guys please help me just retrieving the data i need for each 1,2 : house_no and city
Object.values(address.payload).map(({ house_no, city }) => ({ house_no, city }));
This goes over each value in address.payload and returns an array of objects with house_no and city.
const address = {
id: 301,
payload: {
1: {
house_no: 1234,
city: 'London'
},
2: {
house_no: 0000,
city: 'Paris'
}
}
};
const result = Object.values(address.payload).map(({ house_no, city }) => ({ house_no, city }));
console.log(result);
You can just directly access it as below,
const {1: obj1, 2: obj2} = address.payload;
In here javascript will destructure the payload and assign object 1 into 1 and object 2 into 2. There were some missing commas and quotations in the object which you provided. Therefore I added that also below. Now, obj1 and obj2 will have the 1 and 2 objects where you can extract the data you need out of them easily.
let address = {
id: 301,
payload: {
1: {
house_no: 1234,
city: "London"
},
2: {
house_no: 0000,
city: "Paris"
}
}
};
const {1: obj1, 2: obj2} = address.payload;
console.log(obj1);
console.log(obj1.city);
console.log(obj1.house_no);
You can access object properties directly without looping:
<script>
var obj = {
id: 301,
payload: {
1: {
house_no: 1234,
city: "London"
},
2: {
house_no: 0000,
city: "Paris"
}
}
}
var address1 = obj.payload[1].house_no + " " + obj.payload[1].city;
var address2 = obj.payload[2].house_no + " " + obj.payload[2].city;
</script>

javascript - map with conditionally altered nested field

Given an array such as:
people = [
{
name: 'Bob',
sex: 'male',
address:{
street: 'Elm Street',
zip: '12893'
}
},
{
name: 'Susan',
sex: 'female',
address:{
street: 'Hickory Street',
zip: '00000'
}
}
]
I am trying to write a function which will alter specific instances of '00000' in the nested field 'zip' to the string '12893' and return a new array identical to the initial array except with the corrected values. My attempt at a function so far is:
function zipFix (initialArray) {
return initialArray.map(function(person) {
if(person.address.zip === '00000')
person.address.zip = "12893"
return person
});
}
I know this function is altering the values in 'initialArray', which isn't supposed to happen. How can I go about writing my function so that I can effectively use the map function to create a new, corrected array? Thanks.
While map-ing over the values, you will need to create a copy of each object. The easiest way to do so is with the object spread syntax ({...obj}).
This will "spread" all the values (name, adress, etc) into a new object. So any changes won't mutate it. However, it's "shallow" meaning it will be a new object but its values are the same. So since address is also an object we need to copy that as well, hence the reason for the nested spread of the address value as well.
people = [{
name: 'Bob',
sex: 'male',
address: {
street: 'Elm Street',
zip: '12893'
}
},
{
name: 'Susan',
sex: 'female',
address: {
street: 'Hickory Street',
zip: '00000'
}
}
]
function zipFix(initialArray) {
return initialArray.map(function(person) {
// Create a new "copy" of the person. Using object spread
// will create a "shallow" copy, so since address is also an
// object it will have to be spread (same for other objects that might
// be mutated).
const newValue = { ...person, address: { ...person.address }}
if (newValue.address.zip === '00000') {
newValue.address.zip = "12893";
}
return newValue
});
}
console.log(zipFix(people))
console.log(people) // unchanged
You need to return values from callback function too, also make a copy of element before assigning to avoid mutability
const people = [{name: 'Bob',sex: 'male',address:{street: 'Elm Street',zip: '12893'}},{name: 'Susan',sex: 'female',address:{street: 'Hickory Street',zip: '00000'}}]
function zipFix (initialArray) {
return initialArray.map(function(person) {
let newObj = JSON.parse(JSON.stringify(person))
if(newObj.address.zip === '00000')
newObj.address.zip ="12893"
return newObj
});
}
console.log(zipFix(people))
people = [{
name: 'Bob',
sex: 'male',
address: {
street: 'Elm Street',
zip: '12893'
}
},
{
name: 'Susan',
sex: 'female',
address: {
street: 'Hickory Street',
zip: '00000'
}
}
]
function zipFix (initialArray) {
return (initialArray.map(({address, ...p}) => (
address.zip !== '00000' ? { ...p, address } : {
...p,
address: {
...address,
zip: '12893'
}
}
)));
}
console.log(zipFix(people));
You can do:
const people = [{name: 'Bob',sex: 'male',address: {street: 'Elm Street',zip: '12893'}},{name: 'Susan',sex: 'female',address: {street: 'Hickory Street',zip: '00000'}}]
const zipFix = people.map(({address, ...p}) => ({
...p,
address: {
...address,
zip: address.zip === '00000' ? '12893' : address.zip
}
}))
console.log(zipFix)

Clean Method to Normalize Javascript Object Properties

I have an array of javascript objects that represent users, like so:
[
{ userName: "Michael",
city: "Boston"
},
{ userName: "Thomas",
state: "California",
phone: "555-5555"
},
{ userName: "Kathrine",
phone: "444-4444"
}
]
Some of the objects contain some properties but not others. What I need is a clean way to ensure ALL objects get the same properties. If they don't exist, I want them to have an empty string value, like so:
[
{ userName: "Michael",
city: "Boston",
state: "",
phone: ""
},
{ userName: "Thomas",
city: "",
state: "California",
phone: "555-5555"
},
{ userName: "Kathrine",
city: "",
state: "",
phone: "444-4444"
}
]
Update
I should have been a little more specific. I was looking for an option that would handle this situation dynamically, so I don't have to know the properties ahead of time.
For jQuery specific, the $.extend() option is a good one, but will only work if you know ALL the properties ahead of time.
A few have mentioned that this should probably be a server-side task, and while I normally agree with that, there are two reasons I'm not handling this at the server-side:
1) it will be a smaller JSON object if say 900 of 1000 objects only contain 1 of a possible 9 properties.
2) the "empty" properties need to be added to satisfy a JS utility that could be replaced in the future with something that doesn't care if some properties are missing.
Since you are using jQuery you can abuse $.extend
function Person(options){
return $.extend({
userName:"",
city: "",
state:"",
phone: ""
},options);
}
$.map([{}],Person)
update
Heres a way to have dynamic default properties
function mapDefaults(arr){
var defaultProperties = {}
for(var i =0; i < arr.length; i++){
$.each(arr[i],function(key){
defaultProperties[key] = "";
});
}
function Defaulter(obj){
return $.extend({},defaultProperties,obj);
}
return $.map(arr, Defaulter);
}
mapDefaults([{a:"valA"},{b:"valB"}]);
/* produces:
[{a:"valA",b:""},{a:"",b:"valB"}]
*/
Something you might try is creating a coalescing function:
function coalesceValues(val){
switch(val)
case undefined:
case null:
return '';
break;
default:
return val;
break;
}
}
Or if you wanted to forego customization for simplicity:
function coalesceValues(val){
return val || '';
}
And then apply it when assigning variables:
var city = coalesceValues(obj.city);
This way you don't need to do any crazy breakdown to array and loop or anything, you can apply it to whatever you want, and you can also customize the values you want to coalesce.
Just offering an alternative idea.
The way that is easiest to understand is probably to make a function that accepts an object and uses if statements as existence checks, assigning a default value if it doesn't find it.
function normalize(object) {
if(typeof object.userName === 'undefined') {
object.userName = 'Default Value';
}
if(typeof object.city === 'undefined') {
object.city = 'Default Value';
}
if(typeof object.state === 'undefined') {
object.state = 'Default Value';
}
if(typeof object.phone === 'undefined') {
object.phone = 'Default Value';
}
return object;
}
var userArray = [{},{},{}].map(normalize);
We can also go the constructor route and provide default values on object creation.
function User (data) {
this.userName = data.userName || 'Default Value';
this.city = data.city || 'Default Value';
this.state = data.state || 'Default Value';
this.phone = data.phone || 'Default Value';
return this;
}
var userArray = [{},{},{}].map(function(o){
return new User(o);
});
Of course this depends on one specific type of data and won't extend to other properties and isn't very DRY, but as I said, this is probably the easiest to understand from a beginner's standpoint.
var list = [
{ userName: "Michael",
city: "Boston"
},
{ userName: "Thomas",
state: "California",
phone: "555-5555"
},
{ userName: "Kathrine",
phone: "444-4444"
}
];
for(var i = 0; i < list.length; i++){
if(list[i].state === undefined)
list[i].state = "";
if(list[i].phone === undefined)
list[i].phone = "";
};
console.log(list);
http://jsfiddle.net/g5XPk/1/
This should probably be a server-side task, but..
If you know all the possible properties ahead of time, you could do this:
http://jsfiddle.net/BMau9/
var properties = ['userName', 'city', 'state', 'phone'];
var data = [{
userName: "Michael",
city: "Boston"
}, {
userName: "Thomas",
state: "California",
phone: "555-5555"
}, {
userName: "Kathrine",
phone: "444-4444"
}];
for (var i in data) {
for (var j in properties) {
data[i][properties[j]] = data[i][properties[j]] || '';
}
}
Fiddle
This function stores unique object keys in an array and so you can run your array of objects through it and then use one of the other supplied answers to add the keys to the objects if they do not exist:
function uniqueKeys(){
var keys=[];
function getUniqueKeys(){
return keys
}
function addObject(obj){
for (var k in obj){
keys = _.union(keys,[k]);
}
}
return {
addObj: addObject,
getKeys: getUniqueKeys
}
}
Usage:
var objArr = [{ userName: "Michael", city: "Boston" },
{ userName: "Thomas", state: "California", phone: "555-5555"},
{ userName: "Kathrine",phone: "444-4444" }];
var uniq = new uniqueKeys();
_.each(objArr, function(v){
uniq.addObj(v)
});
var keys = uniq.getKeys();
alert(keys);
vanilla js
let A = [
{
userName: "Michael",
city: "Boston",
},
{
userName: "Thomas",
state: "California",
phone: "555-5555",
},
{
userName: "Kathrine",
phone: "444-4444",
},
];
// set-difference
const diff = (a,b) => new Set([...a].filter((x) => !b.has(x)));
// all keys
const K = new Set(arr.map(o => Object.keys(o)).flat());
// add missing keys and default vals
A.forEach((e,i) => diff(K, new Set(Object.keys(e))).forEach(k => A[i][k] = ""));

Categories

Resources