Basic React form submit refreshes entire page - javascript

I'm trying to create an input form that stores information in a component's state variable, then outputs that variable on the screen. I read the docs on controlled components, and that's what I'm attempting here.
My main issue here is when I click submit, the correct text appears on the screen, but then the entire page refreshes and I'm not sure why. From what I've read online, refs appear to be a solution, but my understanding is that I can use either that, or controlled components.
class InputField extends React.Component {
constructor(props) {
super(props);
this.state = {
itemName: "",
storedItemName: "",
};
this.handleNameChange = this.handleNameChange.bind(this);
this.afterSubmission = this.afterSubmission.bind(this);
}
handleNameChange(event) {
this.setState({
itemName: event.target.value
});
}
afterSubmission(event) {
let name = this.state.itemName;
this.setState ({
storedItemName:this.state.itemName
}, function() {
alert(this.state.storedItemName); // Shows the right value!
});
}
render() {
return(
<div>
<form onSubmit = {this.afterSubmission}>
<label> Item Name:
<input
type = "text"
name = "itemName"
value = {this.state.itemName}
onChange = {this.handleNameChange}
/></label>
<input type = "submit" value = "Submit" />
</form>
<div className = "itemList">
<p>Hi</p>
{this.state.storedItemName}
</div>
</div>
);
}

Just call event.preventDefault method to prevent default behavior of form
afterSubmission(event) {
event.preventDefault();
let name = this.state.itemName;
this.setState ({
storedItemName:this.state.itemName
}, function() {
alert(this.state.storedItemName); // Shows the right value!
}
}

Prevent the default behaviour:
afterSubmission(event) {
event.preventDefault();
let name = this.state.itemName;
this.setState ({
storedItemName:this.state.itemName
}, function() {
alert(this.state.storedItemName); // Shows the right value!
});
}

To prevent basic React form submit from refreshing the entire page, we call e.preventDefault. in the submit event handler.
For instance, we write:
import React from "react";
export default function App() {
const onSubmit = (e) => {
e.preventDefault();
console.log("refresh prevented");
};
return (
<div>
<form onSubmit={onSubmit}>
<button type="submit">submit</button>
</form>
</div>
);
}
to create the onSubmit function that’s set as the value of the onSubmit prop.
In the function, we call e.preventDefault to prevent the default submission behavior, which is to do server side form submission which refreshes the whole page.
We have a submit button in the form to do the form submission.
Therefore, instead of seeing the page refresh when we click submit, we should see the 'refresh prevented' string logged in the console instead.

There are 3 ways you can do this:
1st WAY
By using event.preventDefault(); function
When we use onSubmit() event for form submission the default
behaviour of this event is to refresh the browser and render a new
html page.
To prevent this default behaviour of page refresh for onSubmit event
we put event.preventDefault(); inside the function we are calling for
onSubmit event.
InputField.js
class InputField extends React.Component {
state = {
itemName: "",
storedItemName: "",
}
handleNameChange = (event) => {
const { name,value } = event.target;
//we can't write this.setState({name:value}) this will set name as the key we need value of the name which is itemName
this.setState({
[name] : value //itemName:"the text we will enter"
});
}
afterSubmission = (event) => {
event.preventDefault();
this.setState ({
storedItemName:this.state.itemName
}, function() {
alert(this.state.storedItemName);
});
}
render() {
return(
<div>
<form onSubmit = {this.afterSubmission}>
<label> Item Name:
<input
onChange = {this.handleNameChange}
type = "text"
name = "itemName"
value = {this.state.itemName}
/>
</label>
<input type = "submit" value = "Submit" />
</form>
<div className = "itemList">
<p>Hi</p>
{this.state.storedItemName}
</div>
</div>
);
}
}
export default InputField;
2nd WAY
By removing onSubmit event from form element
Next is change the input type of submit to input type button
and add an onClick event to it
InputField.js
class InputField extends React.Component {
state = {
itemName: "",
storedItemName: "",
}
handleNameChange = (event) => {
console.log(this);
const { name,value } = event.target;
this.setState({
[name] : value
});
}
afterSubmission = () => {
this.setState ({
storedItemName:this.state.itemName
}, function() {
alert(this.state.storedItemName);
});
}
render() {
return(
<div>
<form>
<label> Item Name:
<input
onChange = {this.handleNameChange}
type = "text"
name = "itemName"
value = {this.state.itemName}
/>
</label>
<input
type = "button"
onClick={this.afterSubmission}
value = "Submit"
/>
</form>
<div className = "itemList">
<p>Hi</p>
{this.state.storedItemName}
</div>
</div>
);
}
}
export default InputField;
3rd WAY
By using react form hook (https://www.react-hook-form.com/)
As per docs we have to install the npm module in our development server
npm install react-hook-form
InputField.js
import InputFieldForm from 'location specified';
class InputField extends React.Component {
render() {
return(
<div>
<InputFieldForm />
</div>
);
}
}
export default InputField;
InputFieldForm.js
import React from "react";
import { useForm } from "react-hook-form";
const InputFieldForm = () =>{
const onSubmit = (formData) =>{
alert(JSON.stringify(formData));
console.log(formData);
}
const { register, handleSubmit } = useForm();
return(
<form onSubmit = {handleSubmit(onSubmit)}>
<label> Item Name:
<input
{...register('itemName')}
type = "text"
name = "itemName"
/>
</label>
<input type = "submit" value = "Submit" />
</form>
)
}
export default InputFieldForm;

Related

Why is my react form not working on codesandbox

I created a simple form here https://codesandbox.io/s/xenodochial-frog-7squw
It says You provided a value prop to a form field without an onChange handler. This will render a read-only field. If the field should be mutable use defaultValue.
But there is an onChange handler being passed, so I don't understand. In addition the page reloads when I hit submit, even though preventDefault() is called
Thank you
The issue is this line:
const { str, handleChange, handleSubmit } = this.state;
handleChange and handleSubmit are not part of the state, but are instance methods, so you can pass them like so:
return (
<div className="App">
<Form str={str} onChange={this.handleChange} onSubmit={this.handleSubmit} />
<Table />
</div>
);
On line 25 you do:
const { str, handleChange, handleSubmit } = this.state;
Because of this, handleChange will be bound to this.state.handleChange which will be undefined as you have no property handleChange in your state.
You also forgot to pass the prop name to your Table-component.
I forked your code and updated it here: https://codesandbox.io/s/modest-meninsky-y1sgh
here is the correct Code for you:
import React from "react";
import "./styles/styles.css";
import Form from "./components/Form";
import Table from "./components/Table";
class App extends React.Component {
constructor(props) {
super(props);
this.state = { str: "", desc: false };
console.log(4444);
this.handleChange = this.handleChange.bind(this); //<-- this binding
}
handleSubmit = event => {
event.preventDefault();
console.log("submitted");
};
handleChange = event => {
this.setState({ str: event.target.value });
};
render() {
const { str } = this.state; // <-- FIXED THIS
return (
<div className="App">
<Form str={str} onChange={this.handleChange} onSubmit={this.handleSubmit} />
<Table />
</div>
);
}
}
export default App;

React basic form issue

I am new to React and learning it on my own, I am trying to implement a simple form where the user can provide a name and it will then be store is the state. Once he stop typing and clink on send the the name is store and the fields is
in the input is reset not the state.
This is what i tried and i get
an error saying that cannot read property "then"
changeFun = (e) => {
this.setState({name: e.target.value})
}
submitFun = (e) => {
e.preventDefault()
this.setState({ name: e.target.value})
}
render() {
return (
<input type = "text" value={this.state.name}/>
<button
onSubmit = {(e) =>
this.submitFun(e).then(
() => reset()
)
onchange ={this.changeFun}}>
SEND
</button>
)
}
submitFun is not returning a promise. So you can't use .then after it.
submitFun = (e) => {
e.preventDefault()
// this.setState({name: e.target.value}) should not be here
// because e.target is <button/>
this.setState({name: ''}) // This will reset the input value
}
<button onClick = {this.submitFun} onchange ={this.changeFun}>SEND</button>
In addition you need to use onClick instead of onSubmit for <button> tag.
onSubmit will be used for <form> tag.
what are you trying to achieve is called Controlled Component! more info here.
the base of Controlled Component is basically you have a property in your state and a form element (i.e and input element). then you chain that input value to your state by a function, and that function is going to run on onChange event, to update the state on every change.
something like this:
class App extends React.Component {
constructor(props) {
super()
this.state = {
inputValue: ""
}
}
handleChange = e => {
const _tempValue = e.target.value
e.preventDefault()
this.setState({inputValue: _tempValue})
}
handleSubmit = e => {
const {inputValue} = this.state
e.preventDefault()
// here is your data
// save it to redux or do what ever you want to
console.log(inputValue)
// last thing here is gonna be to reset state after submition
this.setState({inputValue: ""})
}
render() {
const {inputValue} = this.state
return (
<div>
<form onSubmit={this.handleSubmit}>
<input
value={inputValue}
onChange={this.handleChange}
placeholder="type something"
/>
<input type="submit" />
</form>
<p>{inputValue}</p>
</div>
)
}
}
this is a basic implementation of what you want to do, its here: https://codesandbox.io/s/m39w10olnp
on the example that you provide though , you using then that is basically used when that you returning a promise from a function, something like this:
export const giveMeArray= () => {
return new Promise( (res,rej) => {
setTimeout(() => {
res(Object.assign([], myArray))
}, delay);
})
}
so as you can see there is no need to use then here, check my simple example to implement in a better way!

React - Update Value Of Input After Submit

I'm trying to make a feature where a user can edit a submitted value. So to be completely clear:
You would enter some text
Click submit and that value will be pushed into an array
You will be able to see your value on the dom
If you made an error, you can click on that input and change the value, also updating the state of that value in the already pushed array.
On a button click, you will update the state and have a newly edited value.
I'm stuck on the part of changing the state of the value of the pushed items in the array.
For example:
If I were to click on the field of 'Bob', edit it and click submit, the value of whatever I changed it to would also change the state of what was originally in my array to the new value.
This is what I have so far:
import React, { Component } from 'react'
export default class App extends Component {
constructor(props) {
super(props)
this.state = {
notes: ['hello', 'bob'],
val: ''
}
}
submit = () => {
const { notes, val } = this.state
notes.push(val)
this.setState({notes})
}
handleEdit = e => {
console.log(e)
}
render() {
return (
<div>
<input
type="text"
onChange={e => this.setState({val: e.target.value})}
/>
<button onClick={this.submit}>Submit</button>
{this.state.notes.map(item => {
return (
<form onSubmit={e => e.preventDefault()}>
<input
type="text"
defaultValue={item}
onChange={e => this.setState({val: e.target.value})}
/>
<button onClick={() => this.handleEdit(item)}>Submit
Change</button>
</form>
)
})}
</div>
)
}
}
Try this kind of thing :
handleEdit = (item) => {
const notes = this.state.notes.slice();
const index = notes.indexOf(item);
notes[index] = this.state.val;
this.setState({
notes
})
}

React.js Expected onSubmit listener to be a function, instead got type boolean

Can someone please tell me what the hell I am doing wrong here? I am pretty new to React, and everything I have read says that this should work. I am trying to call the function "addItem" when the form is submitted, however the console.log throws the error "Expected onSubmit listener to be a function, instead got type boolean" on page load. Thanks!
import React, { Component } from 'react';
import App from "./App"
import List from "./List"
class AddTodo extends Component{
constructor(){
super();
this.state = {
items: []
}
}
addItem(e){
var itemArray = this.state.items;
itemArray.push({
text: this._inputElement.value,
key: Date.now()
})
this.setState({
items: itemArray
})
this._inputElement.value = "";
console.log(itemArray)
e.preventDefault()
}
render(){
return(
<div className="box-wrapper">
<form onSubmit={this.addItem.bind(this)}>
<input href={(a) => this._inputElement = a} placeholder={this.props.placeHolder} type="text"></input>
<button type="submit">Submit</button>
</form>
<List entries={this.state.items} />
</div>
)
}
}
export default AddTodo;
Try changing your render and addItem to something like this:
addItem(e){
e.preventDefault();
{/* add the rest of the function here */}
}
render(){
return(
<div className="box-wrapper">
<form onSubmit={this.addItem.bind(this)}>
<input
href={(a) => this._inputElement = a}
placeholder={this.props.placeHolder}
type="text"
/>
<button type="submit" onClick={this.addItem.bind(this)}>Submit</button>
</form>
<List entries={this.state.items} />
</div>
)
}
I made two important changes:
Added e.preventDefault(); to the addItem method, which will prevent default behavior.
Added an onClick handler to the "submit" button, with the addItem method passed in as the target executable.
First have to remove event.preventDefault .It is restricting the default behaviour of the webpage.Add a onClick event listener to the submit so that the function executes on button click.
`import React, { Component } from 'react';
import App from "./App"
import List from "./List"
class AddTodo extends Component{
constructor(){
super();
this.state = {
items: []
}
}
addItem(e){
var itemArray = this.state.items;
itemArray.push({
text: this._inputElement.value,
key: Date.now()
})
this.setState({
items: itemArray
})
this._inputElement.value = "";
console.log(itemArray)
// e.preventDefault(); remove this prevent default
}
render(){
return(
<div className="box-wrapper">
<form onSubmit={this.addItem.bind(this)}>
<input href={(a) => this._inputElement = a} placeholder={this.props.placeHolder} type="text"></input>
<button type="submit" onClick={this.addItem.bind(this)}>Submit</button>
</form>
<List entries={this.state.items} />
</div>
)
}
}
export default AddTodo;`
I am not getting any error. But you should put the preventDefault at the top of the addItem, this will prevent from page reload. There is better way to handle the input value by assigning ref attribute to input and accessing via this.refs.refName.
addItem(e) {
e.preventDefault(); //To prevent the page reload on submit
var itemArray = this.state.items;
itemArray.push({
text: this.refs.inputElement.value
});
this.refs.inputElement.value = ""; // clearing the value
}
render() {
return(
<div>
<form onSubmit={this.addItem.bind(this)} >
<input ref="inputElement" placeholder={this.props.placeHolder} type="text"/>
<button type="submit">Submit</button>
</form>
{
this.state.itemArray.map((item) => {
return(<span>{item}</span>)
})
}
</div>
);
}

to call onChange event after pressing Enter key

I am new to Bootstrap and stuck with this problem. I have an input field and as soon as I enter just one digit, the function from onChange is called, but I want it to be called when I push 'Enter when the whole number has been entered. The same problem for the validation function - it calls too soon.
var inputProcent = React.CreateElement(bootstrap.Input, {type: "text",
//bsStyle: this.validationInputFactor(),
placeholder: this.initialFactor,
className: "input-block-level",
onChange: this.handleInput,
block: true,
addonBefore: '%',
ref:'input',
hasFeedback: true
});
According to React Doc, you could listen to keyboard events, like onKeyPress or onKeyUp, not onChange.
var Input = React.createClass({
render: function () {
return <input type="text" onKeyDown={this._handleKeyDown} />;
},
_handleKeyDown: function(e) {
if (e.key === 'Enter') {
console.log('do validate');
}
}
});
Update: Use React.Component
Here is the code using React.Component which does the same thing
class Input extends React.Component {
_handleKeyDown = (e) => {
if (e.key === 'Enter') {
console.log('do validate');
}
}
render() {
return <input type="text" onKeyDown={this._handleKeyDown} />
}
}
Here is the jsfiddle.
Update 2: Use a functional component
const Input = () => {
const handleKeyDown = (event) => {
if (event.key === 'Enter') {
console.log('do validate')
}
}
return <input type="text" onKeyDown={handleKeyDown} />
}
You can use onKeyPress directly on input field. onChange function changes state value on every input field change and after Enter is pressed it will call a function search().
<input
type="text"
placeholder="Search..."
onChange={event => {this.setState({query: event.target.value})}}
onKeyPress={event => {
if (event.key === 'Enter') {
this.search()
}
}}
/>
Pressing Enter in a form control (input) normally triggers a submit (onSubmit) event on the form. Considering that you can handle it this way (having a submit button is optional if you have only one input):
const { useState } = React;
function App() {
const [text, setText] = useState("");
const [submitted, setSubmitted] = useState('');
function handleChange(e) {
setText(e.target.value);
}
function handleSubmit(e) {
e.preventDefault();
setSubmitted(text);
setText("");
}
return (
<div>
<form onSubmit={handleSubmit}>
<input type="text" value={text} onChange={handleChange} />
<input type="submit" value="add" />
</form>
submitted: {submitted}
</div>
);
}
ReactDOM.render(<App/>, document.getElementById('root'));
<script src="https://unpkg.com/react#17.0.2/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom#17.0.2/umd/react-dom.development.js"></script>
<div id="root"></div>
Implicit form submission (submit event on Enter) is performed when:
there's a submit button
there're no submit buttons, but there's only one input
More on it here.
Alternatively you could bind your handler to the blur (onBlur) event on the input which happens when the focus is removed (e.g. tabbing to the next element that can get focus).
You can use event.key
function Input({onKeyPress}) {
return (
<div>
<h2>Input</h2>
<input type="text" onKeyPress={onKeyPress}/>
</div>
)
}
class Form extends React.Component {
state = {value:""}
handleKeyPress = (e) => {
if (e.key === 'Enter') {
this.setState({value:e.target.value})
}
}
render() {
return (
<section>
<Input onKeyPress={this.handleKeyPress}/>
<br/>
<output>{this.state.value}</output>
</section>
);
}
}
ReactDOM.render(
<Form />,
document.getElementById("react")
)
<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>
<div id="react"></div>
React users, here's an answer for completeness.
React version 16.4.2
You either want to update for every keystroke, or get the value only at submit. Adding the key events to the component works, but there are alternatives as recommended in the official docs.
Controlled vs Uncontrolled components
Controlled
From the Docs - Forms and Controlled components:
In HTML, form elements such as input, textarea, and select typically
maintain their own state and update it based on user input. In React,
mutable state is typically kept in the state property of components,
and only updated with setState().
We can combine the two by making the React state be the “single source
of truth”. Then the React component that renders a form also controls
what happens in that form on subsequent user input. An input form
element whose value is controlled by React in this way is called a
“controlled component”.
If you use a controlled component you will have to keep the state updated for every change to the value. For this to happen, you bind an event handler to the component. In the docs' examples, usually the onChange event.
Example:
1) Bind event handler in constructor (value kept in state)
constructor(props) {
super(props);
this.state = {value: ''};
this.handleChange = this.handleChange.bind(this);
}
2) Create handler function
handleChange(event) {
this.setState({value: event.target.value});
}
3) Create form submit function (value is taken from the state)
handleSubmit(event) {
alert('A name was submitted: ' + this.state.value);
event.preventDefault();
}
4) Render
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input type="text" value={this.state.value} onChange={this.handleChange} />
</label>
<input type="submit" value="Submit" />
</form>
If you use controlled components, your handleChange function will always be fired, in order to update and keep the proper state. The state will always have the updated value, and when the form is submitted, the value will be taken from the state. This might be a con if your form is very long, because you will have to create a function for every component, or write a simple one that handles every component's change of value.
Uncontrolled
From the Docs - Uncontrolled component
In most cases, we recommend using controlled components to implement
forms. In a controlled component, form data is handled by a React
component. The alternative is uncontrolled components, where form data
is handled by the DOM itself.
To write an uncontrolled component, instead of writing an event
handler for every state update, you can use a ref to get form values
from the DOM.
The main difference here is that you don't use the onChange function, but rather the onSubmit of the form to get the values, and validate if neccessary.
Example:
1) Bind event handler and create ref to input in constructor (no value kept in state)
constructor(props) {
super(props);
this.handleSubmit = this.handleSubmit.bind(this);
this.input = React.createRef();
}
2) Create form submit function (value is taken from the DOM component)
handleSubmit(event) {
alert('A name was submitted: ' + this.input.current.value);
event.preventDefault();
}
3) Render
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input type="text" ref={this.input} />
</label>
<input type="submit" value="Submit" />
</form>
If you use uncontrolled components, there is no need to bind a handleChange function. When the form is submitted, the value will be taken from the DOM and the neccessary validations can happen at this point. No need to create any handler functions for any of the input components as well.
Your issue
Now, for your issue:
... I want it to be called when I push 'Enter when the whole number has been entered
If you want to achieve this, use an uncontrolled component. Don't create the onChange handlers if it is not necessary. The enter key will submit the form and the handleSubmit function will be fired.
Changes you need to do:
Remove the onChange call in your element
var inputProcent = React.CreateElement(bootstrap.Input, {type: "text",
// bsStyle: this.validationInputFactor(),
placeholder: this.initialFactor,
className: "input-block-level",
// onChange: this.handleInput,
block: true,
addonBefore: '%',
ref:'input',
hasFeedback: true
});
Handle the form submit and validate your input. You need to get the value from your element in the form submit function and then validate. Make sure you create the reference to your element in the constructor.
handleSubmit(event) {
// Get value of input field
let value = this.input.current.value;
event.preventDefault();
// Validate 'value' and submit using your own api or something
}
Example use of an uncontrolled component:
class NameForm extends React.Component {
constructor(props) {
super(props);
// bind submit function
this.handleSubmit = this.handleSubmit.bind(this);
// create reference to input field
this.input = React.createRef();
}
handleSubmit(event) {
// Get value of input field
let value = this.input.current.value;
console.log('value in input field: ' + value );
event.preventDefault();
// Validate 'value' and submit using your own api or something
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input type="text" ref={this.input} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
ReactDOM.render(
<NameForm />,
document.getElementById('root')
);
You can also write a little wrapper function like this
const onEnter = (event, callback) => event.key === 'Enter' && callback()
Then consume it on your inputs
<input
type="text"
placeholder="Title of todo"
onChange={e => setName(e.target.value)}
onKeyPress={e => onEnter(e, addItem)}/>
I prefer onKeyUp since it only fires when the key is released. onKeyDown, on the other hand, will fire multiple times if for some reason the user presses and holds the key. For example, when listening for "pressing" the Enter key to make a network request, you don't want that to fire multiple times since it can be expensive.
// handler could be passed as a prop
<input type="text" onKeyUp={handleKeyPress} />
handleKeyPress(e) {
if (e.key === 'Enter') {
// do whatever
}
}
Also, stay away from keyCode since it will be deprecated some time.
Example of preventing Enter from submitting a form on an input, in my case it was a google maps location autocomplete input
<input
ref={addressInputRef}
type="text"
name="event[location]"
className="w-full"
defaultValue={location}
onChange={(value) => setLocation(value)}
onKeyDown={(e) => {
if (e.code === "Enter") {
e.preventDefault()
}
}}
/>
Here is a common use case using class-based components: The parent component provides a callback function, the child component renders the input box, and when the user presses Enter, we pass the user's input to the parent.
class ParentComponent extends React.Component {
processInput(value) {
alert('Parent got the input: '+value);
}
render() {
return (
<div>
<ChildComponent handleInput={(value) => this.processInput(value)} />
</div>
)
}
}
class ChildComponent extends React.Component {
constructor(props) {
super(props);
this.handleKeyDown = this.handleKeyDown.bind(this);
}
handleKeyDown(e) {
if (e.key === 'Enter') {
this.props.handleInput(e.target.value);
}
}
render() {
return (
<div>
<input onKeyDown={this.handleKeyDown} />
</div>
)
}
}
const [value, setValue] = useState("");
const handleOnChange = (e) => {
setValue(e.target.value);
};
const handleSubmit = (e) => {
e.preventDefault();
addTodoItem(value.trim());
setValue("");
};
return (
<form onSubmit={handleSubmit}>
<input value={value} onChange={handleOnChange}></input>
</form>
);
//You can use onkeyup directly on input field
const inputField = document.querySelector("input");
inputField.addEventListener("keyup", e => {
if (e.key == "Enter") {
console.log("hello");
}
});

Categories

Resources