prevent bootstrap submit button emptying form if error encounterred - reactjs

I am using bootstrap and reactJS and want to build a form.
Consider the following snippet:
const CustomForm = () => {
const [alertText, setAlertText] = ('')
const [username, setUsername] = ('');
const handle_submit = () => {
//treat some possible error
setAlertText('some warnings...')
}
return (
<Form>
{alertText && <Alert className='mb-3' variant="warning" >
{alertText}
</Alert>}
<FormGroup className="mb-3">
<FloatingLabel label='username'>
<Form.Control type='text' name='username' placeholder='username' onChange={e => setUsername(e.target.value)} value={username} />
</FloatingLabel>
</FormGroup>
<Button className='float-end' type='submit' variant='outline-primary' onClick={handle_submit} >Submit</Button>
</Form>
)
}
the problem with that snippet is that when the button is declared as submit, it auto reloads the page and empties the form, or I would like to handle some error before and do all that stuff only if the are no errors.
If I declare the type as button, it works well, but I am a little bit confused. I would like to use the submit attribute; I think it is more appropriate.
So my first question is, I am right to think that ? and the second is, what do I need to change empty the form only if there are no errors?

Short answer:
type='button' is more appropriate in your case.
Long Answer:
As per MDN Documentation, a button will have by default a type of submit. If the type is submit, once clicked, it will submit the request to the server. If the form the submit button is a part of has action property defined, the POST request will be sent to that uri, otherwise it will be sent to the current uri. In your case it will trigger a page redirect to the same page, and that is the reason why your form is reset.
Since you have an event listener attached to the button, and you want to process the event client-side to later sent XHR(AJAX) request, you don't want the button to trigger the request to server. Thus you can safely set it to type='button'.
If for some reason you still need to keep type='submit', you can stop the submit to further propagate in your onClick event handler using:
e.stopPropagation();

Add the onSubmit prop to Form:
<Form onSubmit={handle_submit}>
and in the handle_submit function add the event (e) argument and call the function preventDefault (prevents refresh):
const handle_submit = (e) => {
// Prevent refresh
e.preventDefault();
//treat some possible error
setAlertText('some warnings...')
}

Related

(Using React) Why is the submit button when onClick is performed using onChange events and resulting in empty string? (useState question)

Description:
The submit button calls a function called displayFields. This function then console logs the state of the input fields. The start of the input fields is listened to by onChange that sets the new state.
Before clicking the submit button the input fields when something is entered console logs the current state of the fields and then provides each string character in the console. To my understanding onChange should listen for changes but not console anything. When the button is clicked it should perform the function one time and console the current state of what is entered in fields. Instead when clicked the fields clear and then console an empty string.
I will provide my code and screen shots to help.
const GetQuote = (props) => {
const [name, setName] = useState("");
const [email, setEmail] = useState("");
const [question, setQuestion] = useState("");
const dispFields = () => {
console.log(name + email + question);
};
/*
This is used in case prevent defualt needs used
function handleSubmit(e) {
e.preventDefault(); }
*/
return (
<React.Fragment>
<form
id="quoteForm"
//onSubmit={handleSubmit}
>
<h1 id="quoteTitle"> Quote Help Form </h1>
<p id="quotePar">
{" "}
Please provide your Name, Contact Email, and what products you would
like more information about in this form:{" "}
</p>
<label id="formName" className="Form">
Name:
<input
type="text"
name="name"
onChange={(event) => {
setName(event.target.value);
}}
/>
</label>
<label id="formEmail" className="Form">
Email:
<input
type="text"
name="email"
onChange={(event) => {
setEmail(event.target.value);
}}
/>
</label>
<br />
<label id="formQuestion" className="Form">
What products would you like to know more about:
<input
type="text"
name="help"
onChange={(event) => {
setQuestion(event.target.value);
}}
/>{" "}
</label>
<br />
<br />
<button
id="quoteSubmit"
type="submit"
//funtion is called however seems to constantly call the useState which is used in onchange
//when submit is done returns empty string
onClick={dispFields()}
>
Submit{" "}
</button>
</form>
</React.Fragment>
);
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
onClick={dispFields()} is getting called on every render. If you pass it without calling it (onClick={dispFields} that should only log it to the console when the button is clicked.
You try to alter from
<
button id = "quoteSubmit"
type = "submit"
//funtion is called however seems to constantly call the useState which is used in onchange
//when submit is done returns empty string
onClick = {
dispFields()
} >
Submit < /button>
to
<
button id = "quoteSubmit"
type = "button"
//funtion is called however seems to constantly call the useState which is used in onchange
//when submit is done returns empty string
onClick = {()=>
dispFields()
} >
Submit < /button>
Changed "button" from "submit", arrow function involved
Both solutions provided above work. Changing to example = {example} from example = {example()}. Also calling it from a arrow function also works. The issue is a node issue. What happens when the use breakpoints is set on the function, the values are console logged however after they are console logged the form refreshes and then the state refreshes so the console logs are never logged because the browser processes the value of event and clears the event at the same time. So as long as the values can be passed to the backend, the front end can remain clearing the value being rendered.

How to Link A certain Keyboard Key to a function in React JS

I have made an App that is simple you can check it out here but the problem is now that when a user is logged in and creating a post there is a button that adds a post now I want "Enter" key to perform the same task the code to my button is
<Button variant="contained" color="secondary" onClick = {updateList}>Add item</Button>
now I want to bind the same updateList function to Enter key please guide me on how can I do that???
The button is from Material-ui
also currently as I click enter key it reloads the page I also want to stop that from happening
Also, can anyone tell me that is it possible to take multikey stroke input like ctrl + Z ?
If you want to bind function to some key you can do it by event listeners called onKeyDown or onKeyPress:
handleKeyPress = (event) => {
if(event.key === 'Enter'){
console.log('enter press here! ')
}
}
function App(){
return(
<div>
<input type="text" id="one" onKeyPress={this.handleKeyPress} />
</div>
);
}
Because you pager is reloading im guessing your using the HTML form tag. To prevent it the page from reloading your need to prevent the default event behavior after submitting.
<form onSubmit={(event) => {event.preventDefault() /* this stops reloading the page */ }} ></form>
To be able to submit on enter, you should add a button in side the form tag and add type "submit" to it.
<form onSubmit={(event) => {event.preventDefault() /* this stops reloading the page */ }} >
<button type={"submit"}/>
</form>
That should do it.

Alert user before leaving page after inputting some data (Specially in ReactJS)

I am creating a page in which the user needs to enter the details to add the product to the product list. If the user accidentally moves out of that page after inputting some data in the form, confirmation should be mandatory from the user before moving out. But I am struggling with this requirement. I am using the react-hook-form for storing the data in the JSON server.
I am using a state leave, if it true then alert the user before moving out else nothing.
const [leave, setLeave] = useState(false);
Now, I don't know where and how to use this state for displaying the alert box before leaving.
Here my form which will render.
render (
<Form onSubmit={handleSubmit(onSubmit)}>
<Form.Row>
<Form.Group as={Col} className="mr-5">
<Form.Label column>Product Name</Form.Label>
<Form.Control
name="productName"
placeholder="Enter product Name"
required
ref={register}
/>
</Form.Group>
</Form.Row>
<Button variant="success" type="submit" className="text-white mt-5">
Add New Product
</Button>
</Form>
<Prompt when={Leave} message="Are you sure you want to leave ?" /> {/*Here I have promted*/}
);
For simplicity, I have given only one input field. Now function definition of onSubmit is given below.
const onSubmit = (formData) => {
setLeave(true); //here I am setting this true
axios.post("http://localhost:4000/products", formData);
navigation.push({
pathname: "/productList",
state: { added: "pass" },
});
};
This will work when I submitting the form but I want to prompt when the user clicks on the back button or any navigation link.
In functional component of reactjs I used below thing. this worked for me. In my case when leaving current page I want to remove some store data. In that case i used below thing.
useEffect(() => {
return () => {
// you can add your functionality here
};
}, []);
when must be true when you want to interrupt navigation.
I would rename your variable to something like isDirty, initialised as false. I've found since I started naming my boolean flags like this my mind has to do a little less work to understand what it might be being used for.
Flip it to true when the first change is made to the form values. Could be simply a useEffect with formData as a dependency? Check its not already flipped to prevent unnecessary renders.
Flip it back to false when you get a 200 from your submission to allow the subsequent navigation.
I don't think React will re-render before the Prompt gets fired in your current onSubmit, so you may need to figure out a way to navigate after verifying the submission.
Another flag like didSubmit would allow you a code path to render a <Redirect> instead of calling navigation.push(), if that suits.
But otherwise, using your current setup, can can allow navigation when you land on a fresh form (your user hasn't committed any effort yet), navigation will be interrupted if the form is 'dirty', and navigation will happen automatically on the next render after setting didSubmit.
const [isDirty, setIsDirty] = React.useState(false)
const [didSubmit, setDidSubmit] = React.useState(false)
const onSubmit = async (formData) => {
try {
await axios.post('url', formData)
setIsDirty(false)
setDidSubmit(true)
} catch (error) {
// handle your errors
}
}
React.useEffect(() => {
if(!isDirty) setIsDirty(true)
}, [formData])
React.useEffect(() => {
if(didSubmit) navigation.push({ ... })
}, [didSubmit]
return (
// the form...
<Prompt when={isDirty} {...} />
)
I have updated the state isDirty or leave to true when there is a change in the input field of the form as shown below
render (
<Form onSubmit={handleSubmit(onSubmit)}>
<Form.Row>
<Form.Group as={Col} className="mr-5">
<Form.Label column>Product Name</Form.Label>
<Form.Control
name="productName"
placeholder="Enter product Name"
required
onChange={() => setIsDirty(true)} {/* I have updated here*/}
ref={register}
/>
</Form.Group>
</Form.Row>
<Button variant="success" type="submit" className="text-white mt-5">
Add New Product
</Button>
</Form>
<Prompt when={isDirty} message="Are you sure you want to leave ?" />
);
Now inside the onSubmit function, I have updated the isDirty state to false before navigating to the destination.
const onSubmit = (formData) => {
axios.post("http://localhost:4000/products", formData);
setIsDirty(false); //here I am setting this true
navigation.push({
pathname: "/productList",
state: { added: "pass" },
});
};
I'd like to share an important point here that whenever there is a change in input at any point then only isDirty state is true and during submission of the form (all input fields are filled) the state change to false so that it can navigate to another URL.

Get value from textarea input in event object

I have a form with a textarea where users can put comments, and then trigger a onClick (when the form is submitet via the button).However, I cant get the value of the input, for example if a user writes "test", I want it to get into the handleSubmit function.
My form
<form onSubmit={this.handleSubmit.bind(this)} method="POST">
<label>Skicka</label>
<textarea placeholder="Type in comments (allergis etc.)" name ="name" ref ="name"></textarea>
<button className="btn" type="submit">
Send
</button>
</form>
//my handler
public handleSubmit = event => {
event.preventDefault();
console.log(event.name.value)
}
You have to save the textarea value separately in the onChange method of the textarea like this (for class component):
<form onSubmit={this.handleSubmit.bind(this)}
method="POST"
>
<label>Skicka</label>
<textarea
onChange={this.setComments}
placeholder="Type in comments (allergis etc.)"
name="name"
value={this.state.comment}/>
<button className="btn" type="submit">
Send
</button>
</form>
// The save function
const setComments = e => this.setState({comment: e.target.value});
This will save the textarea input in your local state and you can access it in your submit function with this.state.comment.
Hope this helps. Happy coding.
As you are using Uncontrolled Component. You can make use of ref to get value.
handleSubmit = (event) => {
event.preventDefault();
console.log(this.refs.name.value)
}
Demo
Note: In React you should never add method="POST" and action attribute's on form.
Don't add public keyword to your function (if you are not using typescript).
Better approach to work with form values, is Controlled Component
You can fix it by changing the handleSubmit method. Check below updated method.
public handleSubmit = event => {
event.preventDefault();
console.log(event.target.name.value)
}
But if you are work with React application then update the state variable via onChange event.

I cannot clear input on submitting form

I am using reactJs coupled with redux-form.
And also using the semantic ui react library
When i want to submit my form, i don't want my page to be refreshed. Instead i want to reset my form after the submission.
Unfortunately, i can't clear my input whereas i set the state to void the value.
/** Form component **/
<Form onSubmit={handleSubmit(this.handleSubmitAction)}>
<Field name="input" component={renderTitleInput} onChangeAction={this.handleInputChange} defaultValue={this.state.input} />
<input type="submit" name="submit" />
</Form>
/** HandleSubmit function **/
handleSubmitAction = (e) => {
this.setState({input:''})
}
The field remain filled after submitting the form.
Any suggestion ? thanks
What you created is an uncontrolled component, which means that update must be handled through the DOM. To do that you need to add the refattribute to get access to the DOM element in the form submit callback. Here is the changes you need to make.
<Form onSubmit={handleSubmit(this.handleSubmitAction)}>
<Field name="input" component={renderTitleInput} onChangeAction={this.handleInputChange} defaultValue={this.state.input} ref={(input) => this.input = input} />
<input type="submit" name="submit" />
</Form>
/** HandleSubmit function **/
handleSubmitAction = (e) => {
// This can be used when using controlled component.
//this.setState({input:''})
this.input.val = '';
}
But maybe what you want is to handle it as controlled component.
I had a similar issue and I want to clear input after submit button is clicked & use the functional component. here is an example of how I reset the value of input field after submitting.
Set value of the input to state value & when state value is reset input field get reset and the field is empty.
const [cancelInput, setCancelInput] = useState('');
const inputChange = (event, data) => {
// console.log(data)
setCancelInput(data.value)
}
const handleClick = (e) => {
setCancelInput(e.target.value)
}
<Input onChange={inputChange} placeholder='Type cancel here' value={cancelInput}/>
<Button color='red' onClick={handleClick} disabled={cancelInput !== 'cancel'} loading={loading} >Cancel</Button>

Resources