onSubmit event handler not working in Reactjs form - javascript

I am new to react and have this form:
class CustomForm extends React.Component {
handleFormSubmit = (e) => {
e.preventDefault();
const title = e.target.elements.title.value;
const content = e.target.elements.content.value;
console.log(title, content)
}
render() {
return (
<div>
<Form onSubmit={ this.handleFormSubmit }>
<FormItem label='Title'>
<Input name='title' placeholder='Put a title here' />
</FormItem>
<FormItem label='Content'>
<Input name='content' placeholder='Enter some content' />
</FormItem>
<FormItem>
<Button type='primary' htmlType='submit'>Submit</Button>
</FormItem>
</Form>
</div>
)
}
}
The form is not submitting anything/nothing in console log. I tried it with onSubmitCapture and that seems to work. How do I fix this?

From your code it looks like you are using some custom component <Form>.. this is not the normal <form> because custom <Form> component might not have the prop onSubmit. Go through the documentation of the component you are using.

button with type='submit' will trigger the form onSubmit Handler

You need to bind the event handlers in the constructor in order to work. Read more here https://reactjs.org/docs/handling-events.html:
class CustomForm extends React.Component {
constructor(props) {
super(props)
this.handleFormSubmit = this.handleFormSubmit.bind(this)
}
handleFormSubmit = (e) => {
e.preventDefault();
const title = e.target.elements.title.value;
const content = e.target.elements.content.value;
console.log(title, content)
}
render() {
return (
<div>
<Form onSubmit={ this.handleFormSubmit }>
<FormItem label='Title'>
<Input name='title' placeholder='Put a title here' />
</FormItem>
<FormItem label='Content'>
<Input name='content' placeholder='Enter some content' />
</FormItem>
<FormItem>
<Button type='primary' htmlType='submit'>Submit</Button>
</FormItem>
</Form>
</div>
)
}
}

Related

ReactJS event.target.value returns as undefined

I've made a form in ReactJS with one text input and when it submits I want to get its value and put it into a variable. But when I console.log() it returns as undefined. How do I fix this? Here is my code.
class App extends Component {
state = {
todoTitle: ""
};
render() {
return (
<div>
<center>
<form
onSubmit={(event) => {
event.preventDefault();
this.setState(todoTitle: event.target.value,);
console.log(this.state.todoTitle); // Returns "undefined"
}}
>
<input
type="text"
autocomplete="off"
class="form-control"
name="todoInput"
placeholder="Enter todo"
style={{ width: "400px", height: "50px" }}
/>
<input
type="submit"
value="Submit"
id="submitButton"
></input>
</form>
</center>
}
}
}
You need to either make a controlled input or useRef for un-controlled input for the React to keep track of your todoTitle state.
To make a controlled input, you will need to use onChange event and a value={this.state.todoTitle} property.
Also on your form, it is best to add an onSubmit event. There is however an option to set the submit on the form submit button also. In that case we need to use onClick={this.handleSubmit} as follows <input type="submit" value="Submit" id="submitButton" onClick={this.handleSubmit} />.
The below code will work for you:
class Form extends React.Component {
state = {
todoTitle: "",
};
handleSubmit = (e) => {
e.preventDefault();
console.log(this.state.todoTitle);
};
render() {
return (
<div>
<form onSubmit={this.handleSubmit}>
<input
type="text"
autocomplete="off"
class="form-control"
name="todoInput"
placeholder="Enter todo"
style={{ width: "400px", height: "50px" }}
value={this.state.todoTitle}
onChange={(e) => this.setState({ todoTitle: e.target.value })}
/>
<input type="submit" value="Submit" id="submitButton" />
</form>
</div>
);
}
}
You can modify your app a bit to get the value on onChange of input textfield, and then store it in the array in case of below example:
export default class App extends React.Component {
state = {
todoTitle: "",
todoList: []
};
render() {
return (
<div>
<center>
<form
onSubmit={event => {
event.preventDefault();
this.setState(
{
todoList: [...this.state.todoList, this.state.todoTitle]
},
() => {
console.log(this.state.todoList);
}
);
}}
>
<input
type="text"
autocomplete="off"
class="form-control"
name="todoInput"
placeholder="Enter todo"
onChange={event => {
this.setState({ todoTitle: event.target.value });
console.log(event.target.value);
}}
style={{ width: "400px", height: "50px" }}
/>
<input type="submit" value="Submit" id="submitButton" />
</form>
</center>
</div>
);
}
}
Full app here: Stackblitz
There are a few other errors with your code, but I will just answer your question.
setState triggers a re-render, so your state isn't available to log until the next time it runs. You can just log what you put in setState.
console.log(event.target.value);
This question has more info.
setState doesn't update the state immediately
Also, you can do a callback.
this.setState({ todoTitle: event.target.value }, () =>
console.log(this.state.todoTitle)
);
Try this:
class App extends React.Component {
constructor(props) {
super(props);
this.state = { todoTitle: "" };
this.handleSubmit = this.handleSubmit.bind(this);
this.handleChange = this.handleChange.bind(this);
}
handleChange(event) {
event.preventDefault();
this.setState({ todoTitle: event.target.value });
}
handleSubmit(event) {
event.preventDefault();
console.log(this.state.todoTitle);
}
render() {
return (
<div>
<center>
<form onSubmit={this.handleSubmit}>
<input
type="text"
autocomplete="off"
class="form-control"
name="todoInput"
placeholder="Enter todo"
style={{ width: "400px", height: "50px" }}
onChange={this.handleChange}
/>
<input type="submit" value="Submit" id="submitButton" />
</form>
</center>
</div>
);
}
}
This will change the state on input changes and then logs on submit the state. An alternative would be to just get the input element and its value via getElementById or something similar in React.
Your code was also not very well formatted and a lot of closing tags missed.
Read more here:
Get form data in ReactJS

How can i connect a submit button to 2 inputs in react?

I've tried using onSubmit on both the inputs and the submit button but I know that's wrong. and I've tried connecting the functions to the inputs. I've seen examples of people using https links to get it posted but I just want to be able to change the color and text when you click submit.
this.state = {
deftextcolor: "green",
text: "Color Me"
}
}
colorchanger(newcolor) {
this.setState({deftextcolor: newcolor})
}
textchanger(newtext) {
this.setState({text: newtext})
}
render() {
return (
<div className='colorer-wrapper'>
<h1 style={{color: this.state.deftextcolor}}>{this.state.text}</h1>
<input type="text"/>
<input type="text"/>
<button type="submit">Submit</button>
</div>
);
}
}
here some example:
const App =()=>{
const [state,setState] = React.useState({bgColor:"",textColor:"",color:"white",backgroundColor:"red"});
const handleChange = (e)=>{
const {target} = e
setState(current =>({...current,[target.name]:target.value}))
}
const onSubmit = (e)=>{
e.preventDefault();
if(state.bgColor.length>0 && state.textColor.length>0)
setState((current)=>({bgColor:"",textColor:"",color:current.textColor,backgroundColor:current.bgColor}))
}
return (<div><form style={{backgroundColor:state.backgroundColor,color:state.color}} onSubmit={onSubmit}>
<div>test style color</div>
<input type="text" name="bgColor" placeholder="background color" value={state.bgColor} onChange={handleChange}/>
<input type="text" name="textColor" value={state.textColor} onChange={handleChange} placeholder="text color"/>
<button type="submit">Apply style </button>
</form></div>)
}
ReactDOM.render(<App/>,document.getElementById("root"))
form{
width:100vw;
height:100vh
}
<script src="https://unpkg.com/react#16/umd/react.production.min.js" crossorigin></script>
<script src="https://unpkg.com/react-dom#16/umd/react-dom.production.min.js" crossorigin></script>
<div id="root"></div>
remenber you need to store event in variable because react update state asynchronously so the event will be gone.
Two places you can wire with onSubmit,
wire it with a button directly
<button onClick={onSubmit} />
wire it with form
<form onSubmit={onSubmit}>
<button type="submit" />
</form>
Your function needs to look like
const onSubmit = (e) => {
// do something. here
}
In your case, you also want to pass something into this function, so either calling handleSubmit directly or <button onClick={ e=> { colorchanger(color) } />
Like this:
import React from 'react';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
deftextcolor: "green",
text: "Color Me",
defInput: '',
textInput: ''
}
}
handleChange = (e) => {
this.setState({[e.target.id]: e.target.value})
}
handleSubmit = () => {
this.setState((state) => ({
deftextcolor: state.defInput,
text: state.textInput,
defInput: '',
textInput: ''
}))
}
render() {
return (
<div className='colorer-wrapper'>
<h1 style={{color: this.state.deftextcolor}}>{this.state.text}</h1>
<input type="text" value={this.state.defInput} onChange={this.handleChange} id="defInput"/>
<input type="text" value={this.state.textInput} onChange={this.handleChange} id="textInput"/>
<button type="submit" onClick={this.handleSubmit}>Submit</button>
</div>
);
}
}
export default App
You can attach the same method to both inputs to update state input values, and then another method to the button that uses state input values to update your other state properties.

How to create a dynamic input type component

I'm developing a dynamic component where the input can be used for several types: text, password, number, date, etc. The idea is to use this input, no matter the type and where to implement it, as long its adaptable. I thought using state was a nice idea, but I have no clue how to do this. Any thoughts?
import React, { Component } from 'react';
import './styles.css';
export default class InputField extends Component {
constructor(props) {
super(props);
this.state = {
name: '',
password: false,
type: ''
}
}
render () {
return (
<div>
<label className='f-size'>{this.state.name}</label>
<input
className='input'
name={this.state.name}
placeholder={this.state.name}
value={this.props.value}
type={this.state.type}
onChange={this.props.onChange}
/>
<span className="errorMessage">{this.props.error}</span>
<span className="errorMessage">{this.props.missField}</span>
</div>
)
}
}
Thank you!
I personally think you should control this via props, seeing as the value will only be meaningful to the Input's parent.
I used this
const InputField = ({
name,
placeholder,
value,
type,
onChange,
error,
missField
}) => (
<div>
<label className="f-size">{name}</label>
<input
className="input"
name={name}
placeholder={placeholder}
value={value}
type={type}
onChange={onChange}
/>
<span className="errorMessage">{error}</span>
<span className="errorMessage">{missField}</span>
</div>
);
Parent component:
class App extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
}
state = {
value: '',
password: '',
};
handleChange(event) {
this.setState({ [event.target.name]: event.target.value });
}
render() {
return (
<div className="App">
<InputField
value={this.state.value}
type="number"
name="value"
onChange={this.handleChange}
/>
<InputField
value={this.state.password}
type="password"
name="password"
onChange={this.handleChange}
/>
</div>
);
}
}
Code Sandbox: https://codesandbox.io/s/y4ljv75k9
Edited to used a stateless component. Not sure if you want state to handle error messages but from your example, this is a valid solution.
<InputField type="text" />
<InputField type="password" />
<input
className='input'
name={this.state.name}
placeholder={this.state.name}
value={this.props.value}
type={this.props.type}
onChange={this.props.onChange}
/>
I would use props to change the type and manage the component.
You could then control the component from a form definition
You should use props not state, so you can pass
<InputType type="text" />
<InputType type="password" />
<InputType type="number" />
and for the other params you can use props also.
You could use this.props.type but the standard jsx input component is already dynamic as you can see from my example below :
var root = document.getElementById('root');
class InputField extends React.Component {
render() {
return (
<div>
<input type={this.props.type} />
</div>
)
}
}
class App extends React.Component {
render() {
return (
<div>
<input type='date' />
<InputField type='password'/>
</div>
)
}
}
ReactDOM.render(<App />, root)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id='root'></div>
Is there a reason why you would like to use a custom input component?

Handle submit and change from child component in react

I have two components :
LoginForm which is used to render the form to login in the app
LoginPage which get the data entered in the LoginForm component and send it to a server
For the moment I would like to handle the form submit and the change of an input value. I read these two articles in the react official website to help me :
https://reactjs.org/docs/lifting-state-up.html
https://reactjs.org/docs/forms.html
But I still don't detect the submit and the change from the LoginPage component when I'm entering a value in LoginForm.
Can you help me to see where is my mistake ?
Thanks by advance.
My two components :
LoginPage.js
class LoginPage extends Component {
constructor(props) {
super(props);
this.state = {
login: true, //switch between Login and SignUp
email: '',
password: '',
firstName: '',
lastName: ''
};
this.handleSubmit = this.handleSubmit.bind(this);
this.handleInputChange = this.handleInputChange.bind(this);
}
handleSubmit(){
alert("SUBMIT");
}
handleInputChange(event) {
alert("YOUHOU");
const target = event.target;
const value = target.value;
const name = target.name;
this.setState({
[name]: value
});
alert("YEEEP");
}
render(){
return (
<div>
<div>
{this.state.login ?
<Login onSubmit={this.handleSubmit} onChange={this.handleInputChange}/>
:
<Register />
}
</div>
<a
onClick={() => this.setState({ login: !this.state.login })}
>
{this.state.login ? 'Besoin d\'un compte ?' : 'Déjà un compte ?'}
</a>
</div>
)
}
}
LoginForm.js
class LoginForm extends Component {
render(){
return (
<div>
<Card>
<form onSubmit={this.props.handleSubmit}>
<div>
<div>
<TextField name="email" floatingLabelText="Email" errorText="Champ obligatoire" type="text" onChange={this.props.handleInputChange}/>
</div>
<div>
<TextField name="password" floatingLabelText="Mot de passe" errorText="Champ obligatoire" type="password" onChange={this.props.handleInputChange} />
</div>
<CardActions>
<div>
<RaisedButton label="Se connecter" primary={true} type="submit" fullWidth />
</div>
</CardActions>
</div>
</form>
</Card>
</div>
);
}
}
handleInputChange is passed down to LoginForm as onChange prop and similarly handleSubmit is passed down by the name onSubmit and hence you need to use it like
class LoginForm extends Component {
render(){
return (
<div>
<Card>
<form onSubmit={this.props.onSubmit}>
<div>
<div>
<TextField name="email" floatingLabelText="Email" errorText="Champ obligatoire" type="text" onChange={this.props.onChange}/>
</div>
<div>
<TextField name="password" floatingLabelText="Mot de passe" errorText="Champ obligatoire" type="password" onChange={this.props.onChange} />
</div>
<CardActions>
<div>
<RaisedButton label="Se connecter" primary={true} type="submit" fullWidth />
</div>
</CardActions>
</div>
</form>
</Card>
</div>
);
}
}

Redux form defaultValue

How to set defaultValue to input component?
<Field name={`${prize}.rank`} defaultValue={index} component={Input} type='text'/>
I tried like above but my fields are empty. I'm trying to create fieldArray (dynamic forms):
{fields.map((prize, index) =>
<div key={index} className="fieldArray-container relative border-bottom" style={{paddingTop: 35}}>
<small className="fieldArray-title marginBottom20">Prize {index + 1}
<button
type="button"
title="Remove prize"
className="btn btn-link absolute-link right"
onClick={() => fields.remove(index)}>Delete</button>
</small>
<div className="row">
<div className="col-xs-12 col-sm-6">
<Field name={`${prize}.rank`} defaultValue={index} component={Input} type='text'/>
<Field name={`${prize}.prizeId`} defaultValue={index} component={Input} type='text'/>
<Field
name={`${prize}.name`}
type="text"
component={Input}
label='Prize Name'/>
</div>
<div className="col-xs-12 col-sm-6">
<Field
name={`${prize}.url`}
type="text"
component={Input}
label="Prize URL"/>
</div>
<div className="col-xs-12">
<Field
name={`${prize}.description`}
type="text"
component={Input}
label="Prize Description" />
</div>
</div>
</div>
)}
On redux forms you can call initialize() with an object of values like so:
class MyForm extends Component {
componentWillMount () {
this.props.initialize({ name: 'your name' });
}
//if your data can be updated
componentWillReceiveProps (nextProps) {
if (/* nextProps changed in a way to reset default values */) {
this.props.destroy();
this.props.initialize({…});
}
}
render () {
return (
<form>
<Field name="name" component="…" />
</form>
);
}
}
export default reduxForm({})(MyForm);
This way you can update the default values over and over again, but if you just need to do it at the first time you can:
export default reduxForm({values: {…}})(MyForm);
This jsfiddle has an example
https://jsfiddle.net/bmv437/75rh036o/
const renderMembers = ({ fields }) => (
<div>
<h2>
Members
</h2>
<button onClick={() => fields.push({})}>
add
</button>
<br />
{fields.map((field, idx) => (
<div className="member" key={idx}>
First Name
<Field name={`${field}.firstName`} component="input" type="text" />
<br />
Last Name
<Field name={`${field}.lastName`} component="input" type="text" />
<br />
<button onClick={() => fields.remove(idx)}>
remove
</button>
<br />
</div>
))}
</div>
);
const Form = () => (
<FieldArray name="members" component={renderMembers} />
);
const MyForm = reduxForm({
form: "foo",
initialValues: {
members: [{
firstName: "myFirstName"
}]
}
})(Form);
this is my implementation using a HoC
import { Component } from 'react'
import {
change,
} from 'redux-form'
class ReduxFormInputContainer extends Component{
componentDidMount(){
const {
initialValue,
meta,
} = this.props
if(initialValue === undefined || meta.initial !== undefined || meta.dirty) return
const {
meta: { form, dispatch },
input: { name },
} = this.props
dispatch(change(form, name, initialValue))
}
render(){
const {
initialValue,
component: Compo,
...fieldProps
} = this.props
return <Compo {...fieldProps} />
}
}
function reduxFormInputContainer(component){
return function(props){
return <ReduxFormInputContainer {...props} component={component} />
}
}
export default reduxFormInputContainer
and then for exemple:
import reduxFormInputContainer from 'app/lib/reduxFormInputContainer'
InputNumericWidget = reduxFormInputContainer(InputNumericWidget)
class InputNumeric extends Component{
render(){
const props = this.props
return (
<Field component={InputNumericWidget} {...props} />
)
}
}

Categories