Merge objects in javascript into one - javascript

My issue is that I have an initial object with data in the function. The function receives params with values that are into this initial object. I need to update the initial object every time with the data, which comes from params.
The code:
export function saveLocalStorage(params = {}) {
let state = {
firstName: '',
lastName: '',
role: '',
idToken: '',
auth: false,
id: '',
email: '',
phone: '',
organizationId: '',
lastVisit: '',
}
localStorage.setItem('donisi-new', JSON.stringify(state))
}
params have the same names as names in initial object, example:
saveLocalStorage({
firstName,
lastName,
role,
organizationId,
auth: true,
idToken,
lastVisit: moment(new Date()),
})
So, for example, the first time I received the first object with params, for example:
saveLocalStorage({
firstName: 'La La',
lastName: 'Bla Bla'
})
and second time I received object with params:
saveLocalStorage({
role: 'admin',
phone: '+111111111'
})
How to update the initial state and don't delete the values and only update them?
Thanks to everybody.

This is a function I use to merge 2 JavaScript objects:
function mergeObjects(obj, src) {
for (var key in src) {
if (src.hasOwnProperty(key)) obj[key] = src[key];
}
return obj;
}
So if you had these 2 objects:
var obj1 = {name: 'Bob', age: 30};
var obj2 = {name: 'Steve'};
And ran the function:
mergeObjects(obj1, obj2);
It would return:
{name: 'Steve', age: 30}

To achieve this behaviour you can use the ES6's spread operator (...) to merge objects. It will merge the two object. The new fields will be added from both object and existing ones will be updated.
Just replace your
localStorage.setItem('donisi-new', JSON.stringify(state))
with
localStorage.setItem('donisi-new', JSON.stringify({...state, ...params}))
The order of state and params is important here. This orders means state object will be updated with new values which exist in params object.

Part of the problem with updating initial state is you have state defined in the function, so those values can't be updated. One way to address this is to pull state out into its own file and then reference it in your function.
// state.js
export default {
firstName: '',
lastName: '',
role: '',
idToken: '',
auth: false,
id: '',
email: '',
phone: '',
organizationId: '',
lastVisit: '',
};
Then in your function you can reference and update it as necessary. The next time you call saveLocalStorage, the state will have been updated from the previous call.
import * as state from "./state.js";
export function saveLocalStorage(params = {}) {
/* Update state with values from params example
for (const [key, value] of Object.entries(params)) {
state[key] = value;
}
*/
localStorage.setItem('donisi-new', JSON.stringify(state))
}
I leave part of this in a comment because you may have something else in mind for updating state or before merging.

Related

Adding new array in object

I'm working on an application that involves a somewhat complex user registration. Something similar to this.
const [data, setData] = useState({
identity: '',
people: [{
name: '',
address: [{
street: '',
city: ''
}]
}]
})
function addAddress(){
setData({
...data,
people: [
...data.people,
{
address: [
...data.people[0].address,
{
street: '',
city: ''
}
]
}
]
})
}
When a user adds a new address to a person he is registering, he should add a new address to the person and keep the previous data. But it creates a new data array with just the address data, outside of the specified person.
Could someone help me how to do this insertion into the array?
It's not the best solution i guess, but it should work
I'm using here JSON.stringify() and JSON.parse() to deep copy your previous data
function addAddress (newAddress) => {
setData((previousData) => {
let newData = JSON.stringify(previousData);
newData=JSON.parse(newData);
newData.people[0].address.push(newAddress);
return (newData);
});
}

Is there a way to shorten defining v-model data, Vue.js and Laravel

On my edit page of CRUD project, I have a code that fills the form with values of which record is being edited. I use v-model to define HTML inputs, but the code seems too long.
I get the data from the prop, and fill the v-model.
My code that fills v-model
created() {
this.studentData = this.student;
this.first_name = this.student.first_name;
this.last_name = this.student.last_name;
this.student_number = this.student.last_name;
this.phone_number = this.student.phone_number;
this.email = this.student.email;
this.birth_date = moment(this.student.birth_date).format('YYYY-MM-DD');
this.school_name = this.student.school_name;
}
The way I get the data using prop: props: ['student'] and in blade <student-edit-component :student="{{$student}}">
Defining v-models in script
data () {
return {
first_name: '',
last_name: '',
student_number: '',
phone_number: '',
email: '',
birth_date: '',
school_name: '',
};
},
That fills the value on the form inputs with it's data.
Is there a way to shorten this code using props or arrays?
Please help me, I'm so new to Vue
You can change your model of data adding a new layer. For example:
data() {
return {
currentStudent: {
first_name: '',
last_name: '',
student_number: '',
phone_number: '',
email: '',
birth_date: '',
school_name: '',
}
}
},
Then in created you can use simple
created() {
this.currentStudent = this.student;
this.currentStudent.birth_date = moment(this.student.birth_date).format('YYYY-MM-DD');
},
And in all component replace names by names with currentStudne eg in v-models:
first_name -> currentStudne.first_name
You can also read about Vue.$set
https://v2.vuejs.org/v2/guide/reactivity.html
You can use the object studentData, it is working well with v-model.
First, you pass the props like that :
<student-edit-component :student="student"> (no need to use the ${{}}).
Then in the component `StudentEditComponent', you can use :
props: {
student: {
type: Object,
required: true,
default : () => {},
}
}
You should use the type, required and default properties, it is a good practice.
Then
data () {
return {
studentForm: {},
};
},
created() {
this.studentForm = this.student;
}
In the template, you can after that use v-model="studentForm.first_name"

Destructing and/or mass assigning in ES6

I have 2 sources of data. One of the sources is the "template" to what is acceptable for the data. However, the second source may have a large amount of data that I don't care about (100+ properties in the JSON). Here are the schemas:
// Only store the data we care about. Only a small subset of
// data that I need for this particular dataset.
state = {
isDirty: false,
data: {
name: '',
address: '',
city: '',
state: ''
}
}
The second source will have the 4 attributes in the data schema above (plus many many more I don't care about). Currently, I am assigning them like this:
let updatedData = {};
for(const key in this.state.data) {
updatedData[key] = someDataSource[key];
}
this.state.data = updatedData;
Using ES6, and perhaps destructing, is there a better way to mass assign variables like this?
Thanks again!
EDIT
Added for clarification the assignment after the loop.
Lodash pick can be used to pick specific keys, or helper function can be used for same purpose:
const pick = (obj, keys) => Object.keys(obj)
.filter((key) => keys.indexOf(key) >= 0)
.reduce(
(newObj, key) => Object.assign(newObj, { [key]: obj[key] }),
{}
);
This is already suggested in many related questions. The thing that is specific to this question is:
this.state.data = pick(someDataSource, Object.keys(this.state.data));
Properties can be excluded and modified in the JSON.parse reviver :
var o = JSON.parse('{"a":1, "b":2}', (k, v) => k === 'a' ? void 0 : k === 'b' ? 3 : v)
console.log( o )
A trick you can do (trick because it requires to swallow an error) is to use an non extensible object, using the Object.preventExtensions and then use Object.assign to fill it with data (in a try/catch block).
// Only store the data we care about. Only a small subset of
// data that I need for this particular dataset.
state = {
isDirty: false,
data: {
name: '',
address: '',
city: '',
state: ''
}
}
const newData = {
name:'name',
address:'address',
city:'city',
state:'state',
phone:'phone',
zip:'zip'
}
const updatedData = Object.preventExtensions({...state.data});
try{
Object.assign(updatedData, newData);
} catch(throwaway){};
console.log(updatedData);
And as a function for reuse
function schemaMerge(schema, data) {
const mergedData = Object.preventExtensions({...schema});
try {
Object.assign(mergedData, data);
} catch (throwaway) {};
return ({...mergedData}); // create a new object from the merged one so that it no longer is extensionless
}
// Only store the data we care about. Only a small subset of
// data that I need for this particular dataset.
state = {
isDirty: false,
data: {
name: '',
address: '',
city: '',
state: ''
}
}
const newData = {
name: 'name',
address: 'address',
city: 'city',
state: 'state',
phone: 'phone',
zip: 'zip'
}
const updatedData = schemaMerge(state.data, newData);
state.data = updatedData;
console.log(state.data);

Object destructuring to a named object

I'm trying to destructure an object using the following code.
const searchdata = {
org,
packageName,
description,
keywords
} = this.state;
but I get the following error.
Uncaught ReferenceError: org is not defined
What am I doing wrong here? could we destruture and object into another named object?
added a sample of the state object
this.state = {
searchKey: '',
onValueChange: false,
org: '',
packageName: '',
description: '',
keywords: '',
};
You can do it by way of elimination using object rest:
const state = {
searchKey: '',
onValueChange: false,
org: '',
packageName: '',
description: '',
keywords: '',
};
const {
searchKey,
onValueChange,
...searchdata
} = state;
console.log(searchdata);

How can I properly set object values inside a promise?

So I have this object:
let user = {
name: null,
age: null,
sex: null,
created_at: null
}
and I want to set the values based on what the promise returns. The data returned has the same property names.
So the promise is this:
promise.get(/*url*/).then(res => {
const data = res.data;
// set values here
})
I have three ways in my mind right now in setting the property values:
// First
user = data
// Second
user = {
name: data.name,
age: data.age,
sex: data.sex,
created_at: data.created_at
}
// Third
Object.assign(user, data);
Which is the best/proper way? And what are the advantages of one over the other?
I'm currently using the Third option. Any help would be much appreciated.
I like Object.assign()
const user = {
name: 'Ronald Mickdonlad',
age: null,
sex: 'no thanks',
created_at: null
}
const res = {
data: {
name: 'Garbo Hamburgler',
age: 1337,
sex: '0%',
created_at: 133713371337
}
}
//fake DB call
console.log(Object.assign({}, user, res.data))
I was trying to show it with spread operator also, but my REPL apparently doesn't have it, so I gave up. See here:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator
This should work also:
return {
...user,
...res.data
}
But, you will need Babel: https://babeljs.io/docs/plugins/transform-object-rest-spread/
I prefer both of those over any other way because it is immutable. You are not reassigning any variables. You are doing read-only once assigned and then creating new objects as you go.
Both Object.assign() and spread operator have right to left precedence, so "newer aka right-most" values will overwrite "older aka left-occurring" values.
Go with this:
const user = {
name: null,
age: null,
sex: null,
created_at: null
}
// if inside an async function
const updatedUserObj = await promise
.get(/*url*/)
.then(res => Object.assign({}, user, res.data))
console.log(updatedUserObj)
Here are a couple more examples to show you Object.assign() further:
const user = {
name: null,
age: null,
sex: null,
created_at: null
}
const someObject = {
coffee: {
good: true,
flavour: 'ultra',
shouldDrink: true,
age: 1337
}
}
// Notice how coffee is the property on the object we just created:
console.log('FIRST EXAMPLE', JSON.stringify(Object.assign({}, someObject), null, 2))
// Notice how someObject is the property on the new object and coffee is its property
console.log('SECOND EXAMPLE', JSON.stringify(Object.assign({}, { someObject }), null, 2))
// Now, watch what happens if we begin overwriting:
console.log('THIRD EXAMPLE', JSON.stringify(Object.assign({}, user, someObject), null, 2))
console.log('FOURTH EXAMPLE', JSON.stringify(Object.assign({}, { user, someObject }), null, 2))
console.log('FIFTH EXAMPLE', JSON.stringify(Object.assign({}, user, { someObject }), null, 2))
console.log('SIXTH EXAMPLE', JSON.stringify(Object.assign({}, { user }, someObject), null, 2))
Option 3 is the better option. In your example with Object.assign(), you are using a factory function to create new instance of your user. The advantage of this is, it doesn't force you to call a constructor of user when you want to create a new user instance. You could also use Object.create()
This is a basic example of Object Orientated Programming.
Read up more here for a better understanding https://www.sitepoint.com/object-oriented-javascript-deep-dive-es6-classes/

Categories

Resources