Assigned input value is undefined since onChange is never triggered - javascript

I need a solution for following problem ...
When a user registers succesfully, he gets redirected to the login page with email input field filled out and focus on password field. (email is send over paramaters)
Now since onChange event was not triggered (because email was not typed) it's value returns undefined and therefore login fails.
Is there a way to get around this?
You can found my code below
const email = queryString.parse(location.search).email; // returns email correctly
The following is a component so each attribute is set as name={props.name} value={props.value} etc
const handleChange = (name, value) => {
setData((prev) => ({ ...prev, [name]: value }));
};
<InputField name="email" type="email" onChange={handleChange} value={email ? email : ""}
So when everything is typed manually, data gets updated as expected and everything works fine, but when redirected from register to login with the field filled out through email variable, then email in data will be undefined.
Is there a way to trigger onChange when email is placed as a value inside the input field?
Thanks in advance!

The problem is handleChange is not getting the parameters of name and value
You can try something like: (Assuming name is a variable defined)
<InputField name="email" type="email" onChange={(e, {value}) => handleChange(name, value)} value={email ? email : ""}

I make a simple code, but I don't konw what actually you need, you can check on :
Or
import React, { useState } from "react";
const Sample = (props) => {
// const query = window.location.search;
const query = window.location;
const [value, setValue] = useState(query);
const handleValueOnChange = (e) => {
setValue(e.target.value);
};
console.log(query);
return (
<div>
<input onChange={handleValueOnChange} value={value} />
</div>
);
};
export default Sample;
Hope to help you .

Related

Using jest to send text to an input field and update state

Working on a technical challenge again. I want to set up unit tests (don't have to, but I would like to).
Problem is when I try to use userEvent or fireEvent to send some text to an input field, nothing happens (my expect toEqual test fails. I noticed that when I commented out enough of my code to figure out what was going on, I got the error: TypeError: setUsername is not a function when I use userEvent to type some text into the input field.
I assumed this meant I would need to create a mock state (setUsername updates the username state). However, this didn't resolve the issue.
The component I am testing is a child of a parent component Index . So I also tried wrapping this child component under the parent component (the username state is passed down to the child from Index). This didn't resolve the issue.
Here's my code:
const one = <index>
<One/>
</index>
describe("Step One", () => {
it("Can input text", async () => {
render(one);
const mockSetState = jest.fn();
const component ={
setState: mockSetState,
state: {
username: "test"
}
};
const username = screen.getByTestId("username");
const email = screen.getByTestId("email");
await userEvent.type(username, "Emmanuel");
userEvent.type(email, "emmanuelsibanda21#gmail.com")
expect(mockSetState).toEqual({"username": "emmanuelsibanda21#gmail.com"});
// expect(email.value).toEqual("emmanuelsibanda21#gmail.com")
});
});
This is the code in Index:
const [username, setUsername] = useState('')
const [email, setEmail] = useState(null);
return (
...
{
steps === 1 ?
<One
username={username}
setUsername={setUsername}
steps={steps}
setSteps={setSteps}
setSelectedCountry={setSelectedCountry}
selectedCountry={selectedCountry}
setSelectedState={setSelectedState}
selectedState={selectedState}
setSelectedCity={setSelectedCity}
selectedCity={selectedCity}
email={email}
setEmail={setEmail}
profilePic={profilePic}
setProfilePic={setProfilePic}
/> ...
}
Here's the code from One:
export default function One ({username, setUsername, steps, setSteps, setEmail, email, profilePic, setProfilePic}) {
const url = 'http://localhost:3000/api/getPic';
function changeHandler(e) {
setUsername(e.target.value)
}
function emailChange(e){
setEmail(e.target.value)
}
...
return (
<>
...
<div className={styles.description}>
<Input
data-testid="username"
onChange={changeHandler}
placeholder="What is your full name"
value={username}
/>
<Input
data-testid="email"
onChange={emailChange}
placeholder="Please enter a valid email"
value={email}
/>
</div>
{
username && isEmailValid(email) === true?
<Button data-testid="next" onClick={ () => nextStep() }>Next</Button>
: null
}
</main>
</>
)
};
Any ideas

How to clear a React Bootstrap textarea form control after the form is submitted?

I have a form made with React Bootstrap to semply submit a string that will be saved on a DB. It works and the submitted message is saved, but I don't know how to clear the textarea when the message is submitted.
As you can see, what I tried to do is to use the useState hook to set an empty value but after the form is submitted the string is still visible in the textarea. Is there any way to do this?
const Form = (props) => {
const [isLoading, setLoading] = useState(false);
const [value, setValue] = useState(props.value);
const handleSubmit = async event => {
setLoading(true);
event.preventDefault();
const res = await fetch(
// here I call the api
)
result = await res.json();
setValue(null);
setLoading(false);
};
return (
<Form onSubmit={handleSubmit}>
<Form.Group className="mb-3" controlId="text">
<Form.Control as="textarea"
required
type="text"
placeholder=""
defaultValue={value}
/>
</Form.Group>
<Button
variant="primary"
type="submit"
disabled={isLoading}
>
{isLoading ? 'Saving...' : 'Save'}
</Button>
</Form>
)
}
export default Form;
Remove value from props - Form component should hold this state. Then, for controlled input you need to change "defaultValue" to "value" on Form.Control. Also add onChange and set the value. On form submit you can set your value state to empty string, not null:
https://codesandbox.io/s/competent-carson-wupp3i
To my eye, your textarea is currently uncontrolled, and so any changes made to value won't be updated in the Form.Control component.
<Form.Control
as="textarea"
rows={3}
value={value}
onChange={e => {
setValue(e.target.value);
}
/>
Rather than using the defaultValue prop, I would probably use setValue(props.value) to reset value in your handler function.

React Hook Form Controller Issues

I have been using react hook form library with native elements but would like to switch to custom components using the Controller API.
I am having an issue with my custom input component updating React state but not updating the ref inside the form state. Thus, a required field is always marked as invalid and I cannot submit my form.
Here is a demo of my issue: https://codesandbox.io/s/react-hook-form-controller-bofv5
It should log out form data upon submission - but submission never happens because form is not valid.
I think I have narrowed down your issue. First I removed the rules={{ required: true }} from the controller and tried the form. It told me firstName: undefined. Then I commented out the onChange attribute. After that, the form is working fine. It seems that onChange should be used if you want to provide a custom value extractor. The value needs to be returned from the function. An example of a simple input would be this: onChange={([{target}]) => target.value} reference. Additionally, it is important to note that handleSubmit extracts some internal state with the values, like that you don't need to keep track of those yourself.
This updated component seems to be working:
function App() {
const { control, handleSubmit, errors } = useForm();
// const [data, setData] = useState({ firstName: "" });
const onSubmit = data => console.log(data);
// const onChangeHandler = e => {
// const { name, value } = e.target;
// const _data = { ...data };
// _data[name] = value;
// setData(_data);
// };
return (
<>
{/* <p>{JSON.stringify(data)}</p> */}
<form onSubmit={handleSubmit(onSubmit)}>
<Controller
as={Input}
name="firstName"
id="firstName"
label="First Name"
control={control}
// value={data.firstName}
rules={{ required: true }}
errors={errors.firstName}
// onChange={([e]) => onChangeHandler(e)}
/>
<input type="submit" />
</form>
</>
);
}
Just a side note, I've never worked with this library so only trust me as far as you can toss me.

How to edit a form in wizard and save its state for wizard

I am making a wizard in React js. I am already populating data in form using get api call. Now I want to edit the data in form, that retains it's state over the application flow.
Redux-Form allow you to pass custom props into Field so you can use this as a way to pass retrived value from your api into rendered component.
Base on your example link you can do this:
Modify renderField to accept custom prop value (or any other name you want) and pass it into input value.
const renderField = ({
input,
label,
type,
value,
meta: { touched, error }
}) => (
<div>
<label>{label}</label>
<div>
<input {...input} placeholder={label} type={type} value={input.value ?
input.value : value} />
{touched && error && <span>{error}</span>}
</div>
</div>
);
Define state variable and change handler:
const [email, setEmail] = useState("");
const handleChange = e => {
setEmail(e.target.value);
};
The initial value of your field (in this example 'Email') can be retrived from api as follow:
useEffect(() => {
/* your api call to fetch data */
fetch(....)
.then(res => setEmail(res.data));
}, []);
Then in your field set props and set onChange handler
<Field
name="email"
type="email"
component={renderField}
label="Email"
props={{ value: email }}
onChange={handleChange}
/>
Here is a working example: https://codesandbox.io/s/redux-form-wizard-example-7v3iy?file=/WizardFormSecondPage.js

redux-form, validation breaks if using returned function

I'm using redux form and want to do custom validation messages.
I used their example validation project here:
https://codesandbox.io/s/PNQYw1kVy
As is, it works as expected. If I change the validation function for a required field from
const required = value => value ? undefined : 'Required'
to
const required = message => value => value ? undefined : message || 'Required'
and change the validation definition for the name and email from
validate={[ required ]}
to
validate={[ required('Message') ]} or validate={[ required(null) ]}
then it doesn't process the validation.
Why does this happen? To my understanding if we have const myFunc = val => val and const myFunc2 = () => val => val then [myFunc, myFunc2()] would result in an array of 2 functionally identical functions.
Don't use validation function wrapped into another function, every time the form is rendered it will construct a new function, which will cause field to rerender (because this.props.validate !== nextProps.validate).(check this issue on github)
You can use specifically defined instances of parameterized validation rules:
const required = value => value ? undefined : 'Required';
const requiredMessage = required('Message');
<Field
name="username"
type="text"
component={renderField}
label="Username"
validate={requiredMessage}
/>
Also, this is the reason why validation functions that is defined in form component doesn't work.
const FormComponent = (props) => {
const {handleSubmit, submitting} = props;
const required = value => value ? undefined : 'Required'; //this will not work!!!
return <form onSubmit={handleSubmit}>
<Field
name='username'
type='text'
component={renderField}
label='Username'
validate={required}
/>
<div>
<button type="submit" disabled={submitting}>Submit</button>
</div>
</form>;
};

Categories

Resources