Setting Values for State in React - reactjs

Good Afternoon,
I am having an issue setting an object via useState and I really do not understand why. Below is the input that I am using to display the information from the database based on the ?: statement. I am unsure why the state will not update, and it is possible that I am not handling the state properly. Can someone help me understand what I am doing wrong?
const [userUpdate, setUserUpdate] = useState({
firstName: "",
lastName: "",
email: "",
dob: "",
gender: "",
address: {
billing: {
address1: "",
address2: "",
city: "",
state: "",
postalCode: "",
},
shipping: {
address1: "",
address2: "",
city: "",
state: "",
postalCode: "",
},
},
});
<FormGroup widths="equal" id="billing">
<FormField
id="address1"
control={Input}
label="Address Line 1"
placeholder="123 Main Street"
defaultValue={
userUpdate.address.billing.address1
? userUpdate.address.billing.address1
: user.address.billing.address1
}
onBlur={(e) => {
handleChange("b", e);
}}
/>
</FormGroup>
The handleChange -> b is the section of the address that I need to update.. Billing or Shipping etc.
const handleChange = (section, e) => {
const form = e.target.form.id;
if (form === "user") {
console.log(section);
if (section === "b") {
setUserUpdate({
...userUpdate,
address: {
billing: {
[e.target.id]: e.target.value.trim(),
},
},
});
} else if (section === "s") {
setUserUpdate({
...userUpdate,
address: {
shipping: {
[e.target.id]: e.target.value.trim(),
},
},
});
} else {
setUserUpdate({
...userUpdate,
[e.target.id]: e.target.value.trim(),
});
}
}
if (form === "category") {
setCategoryUpdate({
...categoryUpdate,
[e.target.id]: e.target.value.trim(),
});
}
};
console log is showing the correct e.target.id => address1 and e.target.value.trim() => address, but its not updating the state..
now my code is throwing an error on the form default value
×
TypeError: Cannot read properties of undefined (reading 'address1')
GenerateActiveScreen
C:/Development/Picwrist Web Application/client/src/components/screens/user/Dashboard.js:397
394 | control={Input}
395 | label="Address Line 1"
396 | placeholder="123 Main Street"
> 397 | defaultValue={
| ^ 398 | userUpdate.address.shipping.address1
399 | ? userUpdate.address.shipping.address1
400 | : user.address.shipping.address1

Changed ID's for the fields and updated the handleChange state to pass the existing values from the previous state.
const handleChange = (section, e) => {
const form = e.target.form.id;
if (form === "user") {
const id = e.target.id;
const value = e.target.value.trim();
if (section === "b") {
setUserUpdate((userUpdate) => ({
...userUpdate,
address: {
...userUpdate.address,
billing: {
...userUpdate.address.billing,
[id.slice(1)]: value,
},
},
}));
} else if (section === "s") {
setUserUpdate((userUpdate) => ({
...userUpdate,
address: {
...userUpdate.address,
shipping: {
...userUpdate.address.shipping,
[id.slice(1)]: value,
},
},
}));
} else {
setUserUpdate({
...userUpdate,
[e.target.id]: e.target.value.trim(),
});
}
}
if (form === "category") {
setCategoryUpdate({
...categoryUpdate,
[e.target.id]: e.target.value.trim(),
});
}
};

Related

"False" appearing in input after removing its text

After inserting text in input and later removing it completely with backspace "false" appears in it. It cannot be removed - after removing last letter it appears again. It appears in input which are rendered using map() method. The same problem doesn't occur in textarea which is not rendered using this method so I guess the problem lays somewhere here, but I dont have idea where.
export default function AddTodo({ active, setActive }: AddTodoProps) {
const { isDarkMode } = useContext(DarkModeContext);
const [todoDetails, setTodoDetails] = useState({
task: "",
description: "",
name: "",
deadline: "",
});
const { submitTodo, loading, status } = useAddTodoToDb(todoDetails);
const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
setTodoDetails((prev) => {
return {
...prev,
[e.target.id]: e.target.value || e.target.checked,
};
});
};
useEffect(() => {
if (typeof status == "string")
setTodoDetails({
task: "",
description: "",
name: "",
deadline: "",
});
}, [status]);
return (
{todoInputs.map((item) => {
return (
<StyledLabelAndInput
isDarkMode={isDarkMode}
err={status?.includes(item.id)}
key={item.id}
>
<label htmlFor={item.id}>{item.text}</label>
<input
value={todoDetails[item.id as keyof ITodoDetails]}
type={item.type}
id={item.id}
min={today}
onChange={(e) => handleChange(e)}
/>
</StyledLabelAndInput>
);
})}
<label htmlFor="description">Description (optional)</label>
<textarea
value={todoDetails.description}
id="description"
onChange={(e) =>
setTodoDetails((prev) => {
return {
...prev,
description: e.target.value,
};
})
}
/>
The false value is comming from the input's checked attribute.
const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
setTodoDetails((prev) => {
return {
...prev,
[e.target.id]: e.target.value || e.target.checked, /* <--- HERE */
};
});
};
You're trying to get the input's value OR checked, and since the input has no value it's returning the checked attribute, which is false by default.
Instead you'll need to check if the item type is checkbox before using the checked attribute.

Updating a form object with React useReducer

I have a controlled form containing an address object.
const [formData, setFormData] = useReducer(formReducer, {
name: "",
address: { addressLine1: "", city: "", state: "", zip: "" },
phone: "",
contact: "",
});
const formReducer = (state, event) => {
return {
...state,
[event.name]: event.value,
};
};
Updating a form input triggers a handler function.
<input
className={style.bodylessInput}
placeholder=" "
type="text"
maxLength={30}
name="name"
value={formData.name}
onChange={handleChange}
/>
function handleChange(event) {
setFormData({
name: event.target.name,
value: event.target.value,
});
}
I am struggling to update the address fields. Using an input with name="addressLine1" will add a property to the form object rather than update the address.
Any advice on how I can update the address object inside my form object would be appreciated.
You can do as below. input name be like address.addressLine1
function formReducer(state, event) {
if(event.name.startsWith("address") && event.name.split(".").length > 1){
var updateField = event.name.split(".")[1];
return{
...state,
address:
{...state.address, [updateField] : event.value}
}
}
return {
...state,
[event.name]: event.value,
};
}
input:
<input
type="text"
maxLength={30}
name="address.addressLine1"
value={formData.address.addressLine1}
onChange={handleChange}
/>

reactjs alert message and navigate

I want that when i submit my form one i get a form submitted successfully message but when i submit my form it directly submits no message comes you have submitted your form successfully can someone tell me what to do or what i am doing wrong. and if possible on a side note can you tell me how to use the button to navigate to other page when i try that i am directly naviagted to home page.
Code :
const Account2 = () => {
const [menu, setMenu] = useState([])
const [form, setForm] = useState({
kookid: "",
kookname: "",
name: "",
cuisine: "",
foodtype: "",
spicylevel: "",
servings: "",
price: "",
description: "",
})
const menuCollectionRef = collection(db, "menu")
useEffect(() => {
onSnapshot(menuCollectionRef, snapshot => {
setMenu(snapshot.docs.map(doc => {
return {
id: doc.id,
viewing: false,
...doc.data()
}
}))
})
}, [])
const handleSubmit = e => {
e.preventDefault()
if (
!form.kookid ||
!form.kookname ||
!form.name ||
!form.cuisine ||
!form.foodtype ||
!form.spicylevel ||
!form.servings ||
!form.price ||
!form.description
) {
alert("Please fill out all fields")
return
alert("Form Submitted Successfully")
}
addDoc(menuCollectionRef, form)
setForm({
kookid: "",
kookname: "",
name: "",
cuisine: "",
foodtype: "",
spicylevel: "",
servings: "",
price: "",
description: "",
}).then(() => {
})
}
return (
<form onSubmit={handleSubmit}>
<div className="form-group2">
<label>Kook Id</label>
<input
type="text"
placeholder=""
value={form.kookid}
onChange={e => setForm({ ...form, kookid: e.target.value })} />
</div>
<div className="form-group2">
<label>Description</label>
<textarea
placeholder=""
value={form.description}
onChange={e => setForm({ ...form, description: e.target.value })} />
</div>
<center> <div className="buttons2">
<button type="submit">Submit</button>
</div></center>
</form>
</div></>

How can i set value in nested object in React?

how can I set value from text Input to option[0].title when user input? I tried in many way and get error. Please help me to fix this issue.
const [options, setOptions] = useState({
0: {
title: "",
},
2: {
title: "",
1: {
title: "",
}, },
3: {
title: "",
},
title: "", });
let name, value;
const handleChange = (e) => {
name = e.target.name;
value = e.target.value;
setOptions({ ...options, [name]: value }); };
return ( <TextInput
type="text"
name="0"
value={options[0].title}
onChange={handleChange}
required
placeholder="something"
icon="check_box_outline_blank"
/> )
you just have to edit the title in the object:
const handleChange = (e) => {
name = e.target.name;
value = e.target.value;
setOptions({ ...options, [name]: { title: value } });
};
and if you need the previous information from the targeted name, spread within that object too:
setOptions({ ...options, [name]: { ...options[name], title: value } });
Fully working code,
const [options, setOptions] = useState({
0: { title: "" },
2: {
title: "",
1: { title: "" },
},
3: { title: "" },
title: "",
});
const handleChange = (e) => {
const { name, value } = e.target;
options[+name].title = value;
setOptions({...options});
};
return (
<>
<input
type="text"
name="0"
value={options[0].title}
onChange={handleChange}
required
placeholder="something"
icon="check_box_outline_blank"
/>
<input
type="text"
name="2"
value={options[2].title}
onChange={handleChange}
required
placeholder="something"
icon="check_box_outline_blank"
/>
</>
);
I tried to check this on codesandbox and found a solution -
The name that you have updated here is string and the json has number keys. Which was the reason why it wouldn't update on title node. Also you never said .title = value, which is why values got directly updated to the options[0] element
export default function App() {
const [options, setOptions] = useState({
0: {
title: ""
},
2: {
title: "",
1: {
title: ""
}
},
3: {
title: ""
},
title: ""
});
const handleChange = (e) => {
const name = e.target.name,
value = e.target.value;
let updatedOptions = { ...options };
updatedOptions[Number(name)].title = value;
setOptions(updatedOptions);
};
return (
<div className="App">
<input
type="text"
name="0"
value={options[0].title}
onChange={handleChange}
required
placeholder="something"
icon="check_box_outline_blank"
/>
</div>
);
}

Checkbox value in React and MongoDB

What I am seeking to accomplish is to have an optional checkbox in a form that returns false when unchecked and true when checked (in the DB).
However, whenever I view my submission in the console, things appear to be find - just not showing up in Mongo. I have attempted numerous things after searching all day both frontend and backend schema. Any help or insight would be much appreciated.
export default class CreateworkOrder extends Component {
constructor(props) {
super(props);
this.onChangeEmployee = this.onChangeEmployee.bind(this);
this.onChangeDescription = this.onChangeDescription.bind(this);
this.onChangeDuration = this.onChangeDuration.bind(this);
this.onChangeDate = this.onChangeDate.bind(this);
this.handleCheckClick = this.handleCheckClick.bind(this);
this.onSubmit = this.onSubmit.bind(this);
this.state = {
employee: '',
description: '',
duration: 0,
date: new Date(),
employees: [],
isComplete: false
}
}
componentDidMount() {
axios.get('http://localhost:5000/employees/')
.then(response => {
if (response.data.length > 0) {
this.setState({
employees: response.data.map(emp => emp.employee),
employee: response.data[0].employee
})
}
})
.catch((error) => {
console.log(error);
})
}
handleCheckClick = () => {
const complete = !this.state.isComplete;
console.log(complete);
this.setState({ complete: !this.state.isComplete});
}
Then submit below:
onSubmit(e) {
e.preventDefault();
const workOrder = {
employee: this.state.employee,
description: this.state.description,
duration: this.state.duration,
date: this.state.date,
isComplete: this.state.isComplete
}
console.log(workOrder);
axios.post('http://localhost:5000/workOrders/add', workOrder)
.then(res => console.log(res.data)).catch(console.error);
//window.location = '/home';
}
portion of the form to optionally select
<div className="form-group">
<label>Only check box if job has been completed </label>
<input name="isComplete" type="checkbox"
defaultChecked={this.state.isComplete}
onChange={this.handleCheckClick}
className="filled-in" id="filled-in-box"/>
</div>
<div className="form-group">
<input type="submit" value="Create WO" className="btn btn-primary" onSubmit={this.onSubmit}/>
</div>
</form>
DB Model
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const workorderSchema = new Schema({
employee: { type: String, required: true },
description: { type: String, required: true },
duration: { type: Number, required: true },
date: { type: Date, required: true },
isComplete: { type: Boolean, required: false },
},
{
timestamps: true,
});
const WorkOrder = mongoose.model('WorkOrder', workorderSchema);
module.exports = WorkOrder;
but console does show true
You are using the state variable isComplete but setting the state in complete.
this.state = {
employee: '',
description: '',
duration: 0,
date: new Date(),
employees: [],
isComplete: false
}
In handleCheckClick you are doing:
handleCheckClick = () => {
const complete = !this.state.isComplete;
console.log(complete);
this.setState({ complete: !this.state.isComplete}); }
And you are submitting workOrder which is using isComplete, which you didn't change
const workOrder = { employee: this.state.employee, description:
this.state.description, duration: this.state.duration, date:
this.state.date, isComplete: this.state.isComplete }
This should be the reason. So change the handleCheckClick like this:
handleCheckClick = () => {
let complete = !this.state.isComplete;
console.log(complete);
this.setState({ isComplete: complete});
}
Also, I noticed that you are using const keyword and then trying to change its value. const means the value shouldn't change. Use either let or var in future if you want a variable to be mutable

Resources