Unable to deep clone [duplicate] - javascript

This question already has answers here:
How to Import a Single Lodash Function?
(10 answers)
Closed 1 year ago.
I want to make a copy of an object.
Following that, I plan to modify values within the copy but these
modifications should not affect the original object.
Thus I want to make a clone and presently using lodash's deepClone.
But it keeps throwing the following error:
Error!Object(...) is not a function
There is no function within my object. It is just in following structure.
They are just key values where values are either strings or booleans.
const myOriginalObject {
mainKey : {
isMobile: true,
data: {
id: '',
header: '',
flag: '',
desc1: '',
desc2: '',
logo: {
src: '',
alt: '',
},
img: {
src: '',
alt: '',
},
}
}
}
Just to test it out created a random object as follows.
And even this throws same error.
const myOriginalObject = {
b: '',
c: ''
}
This is the implementation to deep copy. myOriginalObject can be either one of above objects.
import { cloneDeep } from 'lodash/cloneDeep';
const myClone = cloneDeep(myOriginalObject);
What am I doing wrong? Pls advice. Thanks.
UPDATE:
My lodash version from package.json
"lodash": "^4.17.20",
Error:
render had an error: TypeError: Object(...) is not a function

try with this
const myOriginalObject {
mainKey : {
isMobile: true,
data: {
id: '',
header: '',
flag: '',
desc1: '',
desc2: '',
logo: {
src: '',
alt: '',
},
img: {
src: '',
alt: '',
},
}
}
}
const newObj = JSON.parse(JSON.stringify(myOriginalObject));
Now make any changes to newObj it will not reflect to myOriginalObject;

Related

I am migrating from apollo-link-state to #apollo/client, how do I write default data to InMemoryCache of #apollo/client without using cache.writeData?

I use react 16.13 and am currently migrating from apollo-client 2.x to #apollo/client 3.1.1. I removed a lot of dependency libraries from my packages.json because most of them are now directly importable from #apollo/client. Everything was going fine until I tossed a big rock named "removal of defaults" while migrating from apollo-link-state.
With #apollo/client 3.x, we import InMemoryCache from #apollo/client directly, which is fine. But the withClientState link is no longer existent and ApolloClient doesn't support default values for local cache. I could not find any guide covering this problem. There is one guide for Angular, but it advises to use cache.writeData to construct the cache. Only problem is, in v3.x of #apollo/client, InMemoryCache doesn't have a writeData method anymore. There is a modify method but it is also not straightforward to use, at least I was not able to make it work for this purpose.
I have a large "defaults" object:
export default {
authentication: {
__typename: 'authentication',
auth: ''
},
UserInfo: {
__typename: 'UserInfo',
employee: {
__typename: 'UserInfoEmployee',
defaultShopId: '',
id: '',
email: '',
image: {
__typename: 'image',
id: '',
url: ''
},
firstName: '',
lastName: '',
manager: '',
boss: ''
},
countryCode: '',
chainId: ''
},
defaultShop: {
__typename: 'defaultShop',
id: '',
name: '',
timeZone: null
},
locale: {
__typename: 'locale',
locale: getBrowserLocale()
},
countries: {
__typename: 'countries',
data: []
},
Products: {
__typename: 'Products',
guid: 0,
ProductTypes: {
__typename: 'ProductTypes',
TypeNumber: 0,
type: ''
},
legacyConfiguration: false,
version: '1.0.0'
},
location: {
__typename: 'location',
pathname: '',
search: '',
hash: null,
action: '',
key: null,
isQueryActive: false,
query: null
}
}
How should I write these default data into InMemoryCache without using cache.writeData?
Use writeQuery instead.
I believe in v3 they moved towards using a common way for setting a default state.
Official docs
const query = gql`
query {
authentication #client {
id
__typename
}
...
}`
cache.writeQuery({
query,
data: {
authentication: {
__typename: 'authentication'
...
}
})
it needs to be written using policies, cache.writeQuery didn't work for me at the time of initialization,
cache.policies.addTypePolicies({
Query: {
fields: {
selectedCurrency: {
read() {
return "USD";
},
},
selectedIndex: {
read() {
return 0;
},
},
bookingFlowStep: {
read() {
return '';
},
},
},
},
});

Update the state of object in reducer

I am new to react js. Here, I do have a functionality where there are three diff rows that can be added or removed. I have a reducer which is like,
const initialState = {
Low: [
{
id: 'L0',
technologyId: 0,
technology: '',
type: '',
count: '',
level: 'EASY'
}
],
Medium: [
{
id: 'M0',
technologyId: 0,
technology: '',
type: '',
count: '',
level: 'Medium'
}
],
High: [
{
id: 'H0',
technologyId: 0,
technology: '',
type: '',
count: '',
level: 'Tough'
}
],
SO, Here, I want to have this as a generic,so, I am trying to add objects on click of the plus and remove on - . So,
Here, I am adding using ,
const tempObj = {
id: tempvar + id,
technologyId: 0,
technology: temp[0].technology,
type: type,
count: '',
level: addtype
}
I create this object now depend upon the addType I add it in that particular array.
I do it using this way,
const addData = [...this.props.lowData[addtype], tempObj];
this.props.addNewTech(addData);
So, Here this ...this.props.lowData[addtype] returns an object not an array, is this the problem ? If yes, It should return an array not the object but how is this returning the object and not an array.
My props.lowData is like ,
an object with three different arrays, I mean same as that of the reducer .,But every time I add it adds that element in the Low array only and not in the medium or high. Can any one help me with this ?
The problem is in the reducer you are only updating the Low property. You need to check what property needs to update. For that you can pass addtype to your action creator like so
this.props.addNewTech({ addData, addtype });
And then in action creator
export function addNewTech(data) {
return {
type: ADD_NEW,
data //is equavalent to data: data (ES6)
}
}
And then in reducer dynamically update the object
case ADD_NEW:
return {
...state,
//here choose the property to be updated dynamically
//replace Low: action.data with below line
[action.data.addtype]: action.data.addData,
error: false,
}
**Note here [action.data.addtype]: action.data.addData we are using computed property names in ES6.

updating value of array of object using lodash

My state object is:
[
{
traveller1_dob: '',
traveller1_firstName:'',
traveller1_isPreviousTraveller: false,
traveller1_surname:'',
traveller1_title: ''
},
{
traveller2_dob: '',
traveller2_firstName:'',
traveller2_isPreviousTraveller: false,
traveller2_surname:'',
traveller2_title: ''
}
]
and my payload is:
{key: "traveller1_firstName", value: "ABC", index: 0}
key is the property of the object that needs to be updated
value: is the value we want to update
index: is the index of the traveller in state array
At the moment this is the way I updated:
let obj = state[payload.index];
obj[payload.key] = payload.value;
return _.unionBy(state, [obj], payload.key);
I am aware its not the best way.
Output should be:
[
{
traveller1_dob: '',
traveller1_firstName:'ABC',
traveller1_isPreviousTraveller: false,
traveller1_surname:'',
traveller1_title: ''
},
{
traveller2_dob: '',
traveller2_firstName:'',
traveller2_isPreviousTraveller: false,
traveller2_surname:'',
traveller2_title: ''
}
]
Ideally I want to get rid of index if it's possible.How would you do this?
You're right, you can get rid of the index, and just map over your state and check hasOwnProperty on each stateItem and compare them to the payload.key. The snippet below should solve your problem:
let state = [{
traveller1_dob: '',
traveller1_firstName: '',
traveller1_isPreviousTraveller: false,
traveller1_surname: '',
traveller1_title: ''
}, {
traveller2_dob: '',
traveller2_firstName: '',
traveller2_isPreviousTraveller: false,
traveller2_surname: '',
traveller2_title: ''
}
];
function updateState(payload) {
const updatedState = _.map(state, stateItem => {
if (stateItem.hasOwnProperty(payload.key)) {
stateItem[payload.key] = payload.value;
}
return stateItem;
});
console.log(updatedState);
return updatedState;
}
const samplePayload = {
key: "traveller1_firstName",
value: "ABC",
index: 0
};
updateState(samplePayload);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"></script>

Generate valid v-model value using dot notation string as object reference to the data

Basically i've made proyxy-component which renders different components based on what the :type is and it works great. The point is that I create a schema of the form controls and a separate data object where the data from the form controls is stored. Everything is working good but i have a problem when formData object contains nested objects.
In my example test.test1
How can i make the v-model value dynamic which is generated based on what the string is.
My Compoennt
<proxy-component
v-for="(scheme, index) in personSchema.list"
:key="index"
:type="scheme.type"
:props="scheme.props"
v-model="formData[personSchema.prefix][scheme.model]"
v-validate="'required'"
data-vv-value-path="innerValue"
:data-vv-name="scheme.model"
:error-txt="errors.first(scheme.model)"
></proxy-component>
Data
data() {
return {
selectOptions,
formData: {
person: {
given_names: '',
surname: '',
sex: '',
title: '',
date_of_birth: '',
place_of_birth: '',
nationality: '',
country_of_residence: '',
acting_as: '',
test: {
test1: 'test',
},
},
},
personSchema: {
prefix: 'person',
list: [
{
model: 'given_names',
type: 'custom-input-component',
props: {
title: 'Name',
},
},
{
model: 'surname',
type: 'custom-input-componentt',
props: {
title: 'Surname',
},
},
{
model: 'test.test1',
type: 'custom-input-component',
props: {
title: 'test 1',
},
},
{
model: 'sex',
type: 'custom-select-component',
props: {
title: 'Sex',
options: selectOptions.SEX_TYPES,
trackBy: 'value',
label: 'name',
},
},
],
},
};
},
I would recomment you to write a vue-method (under the data section) that returns the object for v-model
v-model="resolveObject(formData[personSchema.prefix][scheme.model])"
or
v-model="resolveObject([personSchema.prefix] , [scheme.model])"
There you can do handle the dot-notation and return the proper nested property.
I don't think it's possible directly with v-model, you can take a look at:
https://v2.vuejs.org/v2/guide/reactivity.html
Maybe the best solution would be use a watch (deep: true) as a workaround.
(I would try first to use watch properties inside formData[personSchema.prefix][scheme.model].)

ImmutableJS - update value in a List

I have a Map like this (in ImmutableJS):
{arrayOfValues: [
{one: {inside: 'first in array'}},
{one: {inside: 'second in array'}}
]}
And I want to update the value "inside" in the second entry in the "arrayOfValues" array. How can I do it? This is what I have now and it says "Uncaught Error: invalid keyPath"
theMap.update('arrayOfValues',(list)=>{
return list.setIn([1,'one','inside'],'updated value');
})
I also tried directly this and it didn't work:
theMap.setIn(['arrayOfValues',1,'one','inside'],'updated value');
After several hours of looking for the solution, I appreciate any help. Thank you.
What you are doing is correct (see this JSBin).
const orig = Immutable.fromJS({
arrayOfValues: [
{ one: { inside: 'first in array' } },
{ one: { inside: 'second in array' } },
]
});
const updated = orig.setIn(['arrayOfValues', 1, 'one', 'inside'], 'updated value');
console.log(updated.toJS());
// {
// arrayOfValues: [
// { one: { inside: 'first in array' } },
// { one: { inside: 'second in array' } },
// ]
// }
When you call orig.setIn(), it doesn't modify orig directly. That's the whole purpose of this Immutable library. It doesn't mutate the existing data but creates a new one from the existing one.
Your setIn example works as you should see in this plunkr:
http://plnkr.co/edit/1uXTWtKlykeuU6vB3xVO?p=preview
Perhaps you are assuming the value of theMap will be changed as a result of the setIn?
As these structures are immutable, you must capture the modified value in a new variable as var theMap2 = theMap.setIn(['arrayOfValues',1,'one','inside'],'updated value');
activePane is the index of Object in Array(List) that I had to modify
case CHANGE_SERVICE:
var obj = {
title: '1212121 Tab',
service: '',
tagName: '',
preDefinedApi: '',
methodType: '',
url: '',
urlParams: [{
label: '',
name: '',
value: '',
}],
headers: [{
label: '',
name: '',
value: '',
}],
};
var activePane = state.get('activePane');
var panes = state.setIn(['panes', activePane, 'service'], action.val);
return state.setIn(['panes', activePane, 'service'], action.val);

Categories