This onBlur is not working the way I want - reactjs

Here I want this onBlur to show another text or input field which is working but whenever i clear the value it should be hiding but right now it is not working the way I want. In easy words whenever I enter content in input field and loose the focus it show sub input field but whenever clear it all it should be hiding but it is not working here is the code
<Typography
color="#05445E"
fontFamily="'Jost', sans-serif"
fontSize={15}
>
Email
</Typography>
<Input
fullWidth
name="email"
value={user.email}
onChange={handleChange}
disableUnderline={true}
onBlur={handleOTP}
className={classes.inputEmail}
endAdornment={
<>
{user.clearEmail ? (
<IconButton
onClick={() => clearValue("email", "clearEmail")}
>
<ClearIcon />
</IconButton>
) : (
""
)}
</>
}
/>
{showSecondInput && (
<>
<Typography
color="#05445E"
fontFamily="'Jost', sans-serif"
fontSize={15}
sx={{ mt: "15px" }}
>
Enter OTP
</Typography>
<Input
className={classes.inputEmail}
fullWidth
type="password"
/>
</>
)}
This is the states I have used
const [user, update_user] = useState({
user_name: "",
email: "",
clearUser: false,
clearEmail: false,
});
const clearValue = (key, show) => {
update_user({ ...user, [key]: "", [show]: false });
};
const [showSecondInput, setShowSecondInput] = useState(false);
const handleOTP = (e) => {
const { name:key } = e.target;
if(key === "email") setShowSecondInput({ ...showSecondInput, [key]: "", clearEmail: false });
};
const handleChange = (event) => {
const { name: key, value } = event.target;
if (value) {
if (key === "user_name")
update_user({ ...user, [key]: value, clearUser: true });
else if (key === "email")
update_user({
...user,
[key]: value,
clearEmail: true,
});
} else
update_user({
...user,
[key]: "",
clearUser: false,
clearEmail: false,
});
};
The clearValue function is working smoothly without any problem the problem is on blur event..

You could do this by checking for the name in case you have more onBlur with the handleOTP function. Then checking if the value is a empty string and based on that set the state.
const handleOTP = (e) => {
const { name, value } = e.target;
if (name !== "email") return;
if (value === "") {
setShowSecondInput(true);
} else {
setShowSecondInput(false);
}
};

Related

I want to use onBlur here but I'm making some mistake

Here I want to use onBlur function here but the way I want is whenever I enter the email it should activate onBlur and whenever it is empty the input field should hide it but I'm not getting exact solution for this. Here is the code that I have used..
const [user, update_user] = useState({
user_name: "",
email: "",
clearUser: false,
clearEmail: false,
});
const clearValue = (key, show) => {
update_user({ ...user, [key]: "", [show]: false });
};
const [showSecondInput, setShowSecondInput] = useState(false);
const handleOTP = (e) => {
const { name:key, value } = e.target;
if(key=== "email") setShowSecondInput({ ...showSecondInput, [key]: "", clearEmail: true })
else
setShowSecondInput({...showSecondInput,[key]:"", clearEmail:false});
};
Here is the return/ main code
<Input
fullWidth
name="email"
value={user.email}
onChange={handleChange}
disableUnderline={true}
onBlur={handleOTP}
className={classes.inputEmail}
endAdornment={
<>
{user.clearEmail ? (
<IconButton
onClick={() => clearValue("email", "clearEmail")}
>
<ClearIcon />
</IconButton>
) : (
""
)}
</>
}
/>
{showSecondInput && (
<>
<Typography
color="#05445E"
fontFamily="'Jost', sans-serif"
fontSize={15}
sx={{ mt: "5px" }}
>
Enter OTP
</Typography>
<Input
className={classes.inputEmail}
fullWidth
type="password"
/>
</>
)}

This is first time I'm coming across this onBlur event how can i do it?

I will try to explain best as I can. Here what I want is whenever I enter email in my mail field I want another input field to show just below email section. That is not difficult part difficult part is it should be onBlur event whenever i have entered email after loosing focus it should show another textfield or input field just below that I will show you the picture here is the pic
And here is the code
<Typography
color="#05445E"
fontFamily="'Jost', sans-serif"
fontSize={15}
>
Email
</Typography>
<Input
fullWidth
name="email"
value={user.email}
onChange={handleChange}
disableUnderline={true}
className={classes.inputEmail}
endAdornment={
<>
{user.clearEmail ? (
<IconButton
onClick={() => clearValue("email", "clearEmail")}
>
<ClearIcon />
</IconButton>
) : (
""
)}
</>
}
/>
and here is the state i have used..
const [user, update_user] = useState({
user_name: "",
email: "",
clearUser: false,
clearEmail: false,
});
const handleChange = (event) => {
const { name: key, value } = event.target;
if (value) {
if (key === "user_name")
update_user({ ...user, [key]: value, clearUser: true });
else if (key === "email")
update_user({ ...user, [key]: value, clearEmail: true });
} else
update_user({ ...user, [key]: "", clearUser: false, clearEmail: false });
};
This is first time come across this task it will be great help if anyone can help me with example thank you..

add and remove index of form array similar to query builder

I have a form with three input box and a map method so when I enter to add it create the same form below the button when I remove the specific index then it removes the last index, not that specific one although it shows correct data in the console.
const [formData, setFormData] = useState({
wk: [
{
companyName: "",
reasonForChange: "",
role: ""
}
]
});
const [wkArray, setWkArray] = useState([1]);
you can test the whole code with this URL - https://codesandbox.io/s/angry-star-08hyke?file=/src/App.js
You had to bind the input values with the state so they can be updated when re-rendering according to the state change. So the input should look like:
<input
placeholder="company name"
value={item.companyName}
onChange={(e) => {
let temp = [...formData?.wk];
temp[index].companyName = e?.target?.value;
setFormData({ ...formData, wk: temp });
}}
/>
Here's the working code.
import "./styles.css";
import { useState } from "react";
export default function App() {
const [formData, setFormData] = useState({
wk: [
{
companyName: "",
reasonForChange: "",
role: ""
}
]
});
const [wkArray, setWkArray] = useState([1]);
return (
<>
{console.log(wkArray, formData)}
<button
onClick={() => {
setWkArray([...wkArray, Math.floor(Math.random() * 100)]);
setFormData({
...formData,
wk: [
...formData?.wk,
{
companyName: "",
role: "",
reasonForChange: ""
}
]
});
}}
>
Add
</button>
{formData.wk?.map((item, index) => {
return (
<div key={index} style={{ display: "flex" }}>
{formData.wk?.length >= 1 && (
<button
onClick={(e) => {
setWkArray(
wkArray.filter((_, i) => {
return i !== index;
})
);
setFormData({
wk: formData.wk.filter((_, i) => i !== index)
});
}}
>
X
</button>
)}
<div>
<input
placeholder="company name"
value={item.companyName}
onChange={(e) => {
let temp = [...formData?.wk];
temp[index].companyName = e?.target?.value;
setFormData({ ...formData, wk: temp });
}}
/>
</div>
<div>
<input
placeholder="reason for change"
value={item.reasonForChange}
onChange={(e) => {
let temp = [...formData?.wk];
temp[index].reasonForChange = e?.target?.value;
setFormData({ ...formData, wk: temp });
}}
/>
</div>
<div>
<input
placeholder="role"
value={item.role}
onChange={(e) => {
let temp = [...formData?.wk];
temp[index].role = e?.target?.value;
setFormData({ ...formData, wk: temp });
}}
/>
</div>
</div>
);
})}
</>
);
}
You can see the live demo here: https://codesandbox.io/s/amazing-fermat-jtpcli?file=/src/App.js
I have made some minor changes to improve the code.

Not changing the specified data on update-action

I have an Edit Form in which i can update an already existing element of specified ID.
Let's say im editing this character:
{
"name": "Walter White",
"birthday": "1963-01-07",
"img": "https://upload.wikimedia.org/wikipedia/en/0/03/Walter_White_S5B.png",
"status": "Alive",
"appereance": [1, 2, 3],
"id": 1
}
I want to change the name,birthday,image and status. And i already did that. But I want the apperance array to remain the same. Although, after updating the data, the apperance is being erased.
Does anyone know, what can I do so that the apperance array won't change?
My EditForm code:
const UserEditForm = () => {
let { id } = useParams();
const { user } = useSelector((state) => state.user);
const [state, setState] = useState({
name: "",
birthday: "",
img: "",
status: "",
// appereance: ?????
});
const [error, setError] = useState("");
let history = useHistory();
let dispatch = useDispatch();
const { name, birthday, img, status, apperance } = state;
useEffect(() => {
dispatch(getSingleUser(id));
}, []);
useEffect(() => {
if (user) {
setState({ ...user });
}
}, [user]);
const handleInputChange = (e) => {
let { name, value } = e.target;
setState({ ...state, [name]: value });
};
const handleSubmit = () => {
dispatch(updateUser(state, id));
history.push("/");
setError("");
};
return (
<div>
<Button
style={{ width: "100px", marginTop: "20px" }}
variant="contained"
color="secondary"
type="button"
onClick={() => history.push("/")}
>
Go Back
</Button>
<h2>Edit User</h2>
{error && <h3 style={{ color: "red" }}>{error}</h3>}
<form onSubmit={handleSubmit}>
<TextField
id="standard-basic"
label="Name"
value={name || ""}
name="name"
type="text"
required
onChange={handleInputChange}
/>
<br />
<TextField
id="standard-basic"
name="birthday"
value={birthday || ""}
type="date"
required
onChange={handleInputChange}
/>
<br />
<TextField
id="standard-basic"
label="img"
value={img || ""}
name="img"
type="url"
required
onChange={handleInputChange}
/>
<select
id="standard-basic"
label="status"
value={status || ""}
name="status"
onChange={handleInputChange}
>
<option value={""}>Brak informacji</option>
<option value={"Alive"}>Alive</option>
<option value={"Dead"}>Dead</option>
</select>
<Button
style={{ width: "100px" }}
variant="contained"
color="primary"
type="submit"
onChange={handleInputChange}
>
Update
</Button>
</form>
</div>
);
};
EDIT ADDED REDUCER
const fetchState = {
users: [],
user: {},
};
export const userReducer = (state = fetchState, { type, payload }) => {
switch (type) {
case USERS_FETCH:
return { ...state, users: payload };
case ADD_USER:
return { ...state, users: [...state.users, payload] };
case UPDATE_USER:
return { ...state, users: [...state.users, payload] };
case GET_SINGLE_USER:
return {
...state,
user: payload,
};
default:
return state;
}
};
export const selectedUserReducer = (state = {}, { type, payload }) => {
switch (type) {
case GET_USER:
return { ...state, ...payload };
default:
return state;
}
};

React Hooks custom validation in form cannot update multiple states

If all fields were left empty during the firing of handleValidate(), only the states of confirmPasswordIsError and confirmPassword in error would be updated but the others. I have no idea what went wrong?
function Register() {
const classes = useStyles();
const { handleRegister } = useContext(AuthenticationContext);
const [form, setForm] = useState({
username: '',
password: '',
confirmPassword: ''
})
const [error, setError] = useState({
usernameIsError: false,
usernameError: '',
passwordIsError: false,
passwordError: '',
confirmPasswordIsError: false,
confirmPasswordError: ''
});
const handleValidate = () => {
if (!form.username) {
setError({
...error,
usernameIsError: true,
usernameError: '用戶名稱不能留空'
})
}
if (!form.password) {
setError({
...error,
passwordIsError: true,
passwordError: '密碼不能留空'
})
}
if (!form.confirmPassword) {
setError({
...error,
confirmPasswordIsError: true,
confirmPasswordError: '確認密碼不能留空'
})
return false;
}
// if (form.confirmPassword !== form.password) {
// setError({
// ...error,
// confirmPasswordIsError: true,
// confirmPasswordError: '確認密碼與密碼不相同'
// })
// return false;
// }
return true;
}
const handleChange = (e) => {
const { name, value } = e.target
setForm({
...form,
[name]: value
})
}
const handleSubmit = (e) => {
e.preventDefault();
const isFormValid = handleValidate();
console.log(isFormValid)
if (isFormValid) {
handleRegister(form.username, form.password)
}
}
return (
<Container>
<Grid
container
justify="center"
>
<Grid item>
<Paper className={classes.paper} elevation={3} >
<form noValidate autoComplete="off" onSubmit={handleSubmit}>
<TextField
error={error.usernameIsError}
helperText={error.usernameError}
className={classes.input}
fullWidth
required
name="username"
size="small"
label="帳號"
variant="outlined"
value={form.username}
onChange={handleChange}
/>
<TextField
error={error.passwordIsError}
helperText={error.passwordError}
className={classes.input}
fullWidth
required
name="password"
size="small"
label="密碼"
type="password"
variant="outlined"
value={form.password}
onChange={handleChange}
/>
<TextField
error={error.confirmPasswordIsError}
helperText={error.confirmPasswordError}
className={classes.input}
fullWidth
required
name="confirmPassword"
size="small"
label="確認密碼"
type="password"
variant="outlined"
value={form.confirmPassword}
onChange={handleChange}
/>
<Button className={classes.button} fullWidth variant="contained" color="primary" type="submit">註冊</Button>
</form>
</Paper>
</Grid>
</Grid>
</Container>
)
}
If enqueueing multiple updates within a render cycle use a functional state update so the subsequent updates don't overwrite the previously enqueued updates.
When you use normal updates you are spreading in the error state closed over in callback scope from the current render cycle, so each update blows away the previous update. Functional state updates allow you to update from the previous state.
const handleValidate = () => {
if (!form.username) {
setError(error => ({
...error,
usernameIsError: true,
usernameError: '用戶名稱不能留空'
}))
}
if (!form.password) {
setError(error => ({
...error,
passwordIsError: true,
passwordError: '密碼不能留空'
}))
}
if (!form.confirmPassword) {
setError(error => ({
...error,
confirmPasswordIsError: true,
confirmPasswordError: '確認密碼不能留空'
}))
return false;
}
if (form.confirmPassword !== form.password) {
setError(error => ({
...error,
confirmPasswordIsError: true,
confirmPasswordError: '確認密碼與密碼不相同'
}))
return false;
}
return true;
}

Resources