const [data , setData] = ({firstname:'' , lastname:'' , password:''});
const handleChange = (e) => {
setData({...data , [e.target.name] : e.target.value })
I am new to react and java script and can't figure out why ...data(for destructuring) is used is handlechange() function and what is the use of [] braces in [e.target.name] : e.target.value
In this case, ...data (destructuring) is being used so that other attributes already present in data are not affected by the change to the attribute that triggered the event that is actually calling handleChange().
For example, suppose you have a form that has the fields: "Name", "Age", and "Profession". Suppose you fill the form fields in the same above order. As you fill each form field and handleChange() is called your data object gets updated:
When filling the name:
{ name: "John" }
When filling age:
{ name: "John", age: "20" }
When filling profession:
{ name: "John", age: "20", profession: "student" }
...data (destructuring) is a way to ensure the previous attributes are preserved as you add or update new attributes to the data object.
For the second part of your question, the square brackets are used to ensure javascript will evaluate e.target.name and use its value as the attribute to be added or updated to data. The form input fields for this example, should have the name attributes as "name", "age", and "profession", respectively.
Here is the "long" version of the handleChange function. I think it will help you understand the function mission easier.
cons handleChange = (e) => {
const currentData = data;
currentData[e.target.name] = e.target.value;
setData(currentData)
}
The first is the three dots with an object like ...data. It's almost the same with Object.assign. In this case, it help you create a new object from the value of data.
const data = {firstname:'' , lastname:'' , password:''};
const newData = {...data}; // {firstname:'' , lastname:'' , password:''}
The second is the [] braces. If you want to set a property key from a variable inside the {}. You may use the [] braces to wrap this variable.
const key = 'name';
const a = {[key]: 'John'} // {name: 'John'}.
This is not really related to React, you may get the function like this in other places. Some articles you may read about them:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax
Related
I'm trying to render a dynamic list of fields from a JSON file.
Some fields have to go through this accountFieldMap object I created for key renaming purposes.
For example it finds the key userFirstName1 from the JSON and renders the value of it as firstName at the component.
const accountFieldMap = {
firstName: "userFirstName1",
lastName: "userLastName1",
ID: "userID",
location: `userLocation.city`,
};
The only issue is with the location field.
How can I let JavaScript know that it should render that city nested field and show it as location?
If I understand you correctly, location.city is a path to some value in object.
There are some libraries for this like lodash, which have inbuilt functions that can resolve that, but if you want to do it in vanilla js, you can do it by splitting this string by dot and going through that array to get a value.
const getByPath = (path, obj) => {
const splittedPath = path.split(".");
return splittedPath.reduce((acc, curr) => {
acc = obj[curr];
return acc;
}, obj)
}
So in this case if you have object like
const testObj = {
location: {city: "Kyiv"},
firstName: "Oleg"
}
It will return you "Kyiv" if you will pass into getByPath "location.city" as path. And it will also work in case if there is no nesting, so
getByPath("firstName", testObj)
will return you "Oleg"
you only have to map the array and create a new object;
import fileData from "../path/to/json";
const people = fileData.arrayName.map(person => ({
firstName: person.userFirstName1,
lastName: person.userLastName1,
ID: person.userID,
location: person.userLocation.city,
}));
I created an array called animals containing two objects. I want to get a value from the name variable in the object animals and insert that value in a return statement in the map method. I used ${} to access the variable.
const Animals = [{
name: "Lion",
type: "Carnivore",
},
{
name: "Cow",
type: "Herbivore",
},
];
window.addEventListener("DOMContentLoaded", function() {
let display = Animals.map(function(item) {
return '<h1>${item.name}</h1>';
});
console.log(display);
});
Now I'm supposed to get in the console an array of two items containing the values of the variables -- the result should look like this ['<h1>Lion</h1>', '<h1>Cow</h1>']. But instead I get this ['<h1>${item.name}</h1>', '<h1>${item.name}</h1>']. As you can clearly see, for some reason the ${} was unable to access the variable and get the value. I don't know why this's happening. Console log shows no errors. Plz help me resolve this issue. Thanks in advance.
Check in your code instead of:
'<h1>${item.name}</h1>'
Should be:
`<h1>${item.name}</h1>`
Here is the documentation for Template literals (Template strings)
Demo:
const Animals = [{
name: "Lion",
type: "Carnivore",
},
{
name: "Cow",
type: "Herbivore",
},
]
const display = Animals.map(({ name }) => `<h1>${name}</h1>`)
console.log(display)
Variables inside ${...} structures are template/string literals syntax but in order for them to work they need to be enclosed with backticks instead of single/double quotes.
const animals=[{name:"Lion",type:"Carnivore"},{name:"Cow",type:"Herbivore"}];
window.addEventListener("DOMContentLoaded", function() {
const display = animals.map(function(item) {
return `<h1>${item.name}</h1>`;
});
console.log(display);
});
const Animals = [{
name: "Lion",
type: "Carnivore",
},
{
name: "Cow",
type: "Herbivore",
},
];
window.addEventListener("DOMContentLoaded", function() {
let display = Animals.map(function(item) {
return '<h1>'+item.name+'</h1>';
// return `<h1>${item.name}</h1>`;
});
console.log(display);
});
I have a value, i want to pass it to a function and change the original value from withinf the fuction and show it on the screen... im using react hooks. i dont want to use the state/setState, because the value is like 10 layers deep into a json, so it would be very hard to change it using spread... heres an example of what i want to do:
let data = {
phase:{
document:{
name: 'Example'}
}
}
changeName(phase.document.name)
function changeName(name){
name = "Changed name"
}
after that i want to display the changed name... is there a way of doing this?
You can use lodash.set:
let data = {
phase: {
document: {
name: "Example",
},
},
};
const shallowCopy = { ...data };
lodash.set(shallowCopy, `phase.document.name`, `New Changed Name`);
// You must change the reference in order to render
setState(shallowCopy);
I am currently using array filters to update the nested object.
My structure is -
Category Collection -
{
name:Disease,
_id:ObjectId,
subCategory:[{
name:Hair Problems,
_id:ObjectId,
subSubCategory:[{
name: Hair Fall,
_id:ObjectId
},{
name: Dandruff,
_id:ObjectId
}]
}]
}
I want to update the subsubcategory with id 1.1.1 which I am doing by using array filters.
let query = { 'subCategories.subSubCategories._id': subSubId };
let update = { $set: { 'subCategories.$.subSubCategories.$[j]': data } };
let option = { arrayFilters: [{ 'j._id': subSubId }], new: true };
await Categories.findOneAndUpdate(query, update, option
This code is working fine but array filters change the object id of subsubCategory. Is there any other alternative to do so without changing the ObjectId.
Thanks in advance
You can loop over the keys which you are getting as payload and put inside the $set operator.
const data = {
firstKey: "key",
secondKey: "key2",
thirdKey: "key3"
}
const object = {}
for (var key in data) {
object[`subCategories.$.subSubCategories.$[j].${key}`] = data[key]
}
let query = { 'subCategories.subSubCategories._id': subSubId };
let update = { '$set': object };
let option = { 'arrayFilters': [{ 'j._id': subSubId }], 'new': true };
await Categories.findOneAndUpdate(query, update, option)
Problem is in $set line there you have not mentioned specific fields to be update instead subCategory.$.subSubCategory.$[j] will replace complete object element that matches the _id filter. Hence your _id field is also getting updated. You have to explicitly mention the field name after array element identifier. See example below:
Suppose you want to update name field in subSubCategories from Dandruff to new Dandruff. Then do this way:
let update = { $set: { 'subCategories.$.subSubCategories.$[j].name': "new Dandruff" } };
This will only update name field in subSubCategories array
I have problems with Object.assign and ... spread operator. I need to process values (object with name and value tha are objects).
Example my values object:
{
id: "12",
name: "Hotel MESSI",
email: "myemail#aol.com",
phone: "+001060666661",
otherfields: "{
country: 'ZW',
city: 'Zurick'
}"
}
otherfields comes from graphql , so it's string, i must convert to object.
With my process I look for this result:
{
id: "12",
name: "Hotel MESSI",
email: "myemail#aol.com",
phone: "+001060666661",
country: 'ZW',
city: 'Zurick'
}
The code have more code that I paste here, there is a lot of controls for values and conversion but mainly, the idea is reassing values,
With these two case assign to the same variable is not working:
Case 1, with object.assign
processValues = (values)=>
let newValues = {...values}; //
for (const fieldName in Tables[table].fields) {
let value = values[fieldName];
value = JSON.parse(value);
newValues = { ...newValues, ...value};
console.error('after mix',newValues);
Case 2, with object.assign
processValues = (values)=>
let newValues = Object.assign({}, values}; //
for (const fieldName in Tables[table].fields) {
let value = values[fieldName];
value = JSON.parse(value);
newValues = Object.assign( newValues, value};
console.error('after mix',newValues);
How it's works, when I use a new variable, by example:
newValues2 = Object.assign( newValues, value};
but my idea is not use another variable because , i need to get values and set values for the original variable 'newValues' , if I use another variable the code would be more cumbersome.
I'm using in a project with create-react-app. I don't know if it's a problem with babel, because Object.assign and spread operator are not inmmutable; or yes ?
INFO:
Tables[table].fields is a object with definition por my table structure, there therea lot of rules, but basically i need to know why object and ... does not work
The use of JSON.stringify will not help, as this will produce a JSON string, which will have an entirely different behaviour when spreading it (you get the individual characters of that string).
Here is how you can achieve the result with "otherfields" as the special field (you can add other fields in the array I have used):
const processValues = values =>
Object.assign({}, ...Object.entries(values).map( ([key, val]) =>
["otherfields"].includes(key) ? val : { [key]: val }
));
// Example:
const values = {
id: "12",
name: "Hotel MESSI",
email: "myemail#aol.com",
phone: "+001060666661",
otherfields: {
country: 'ZW',
city: 'Zurick'
}
};
const result = processValues(values);
console.log(result);
The first argument to assign is the target. So it's going to get changed. You can simply pass an empty object for your target if you don't want any of the sources to change.
When you are using first argument as {} then no value will change.
For more please refer it.
https://wecodetheweb.com/2016/02/12/immutable-javascript-using-es6-and-beyond/