multiple input elements in form - React - reactjs

It's a simple form which updates the state object onChange and displays that state object when submitted. I was not able to get it to work when there are multiple input elements.
Can anyone tell me what's wrong in this code?
onSubmit works when there's only one input element, but not when there are multiple!
class ReactForm extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.validate = this.validate.bind(this);
this.state = {
name: "",
email: ""
};
}
handleChange(event) {
event.preventDefault();
const name = event.target.name;
const value = event.target.value;
this.setState({
[name]: value
});
}
validate(event) {
event.preventDefault();
console.log(this.state);
}
render() {
return (
<div>
<form onSubmit={this.validate}>
<div>
<input
type="text"
name="name"
value={this.state.name}
onChange={this.handleChange}
/>
<input
type="email"
name="email"
value={this.state.email}
onChange={this.handleChange}
/>
</div>
</form>
</div>
);
}
}
ReactDOM.render(
<ReactForm />,
document.getElementById("root")
);

You need to have a submit button if you have more than 1 input, you can add a hidden one if you want:
<input type="submit" hidden />
Here's a codesandbox: https://codesandbox.io/s/suspicious-almeida-e3f00
And here is the explanation in detail: Why does a FORM with one text INPUT submit on enter while one with two text INPUTs does not?

I really liked the approach of tudor.
Here is a different approach that can remove the state handling as well. But this may require polyfill for IE and Safari. You can use FormData to access the form values.
new FormData(e.target);
Here is the working sandbox link: https://codesandbox.io/s/long-wind-ybl1w
Hope this helps!

Please add an element input and button. Button should have type="submit" for submitting!
It will work!

Related

ReactJS: Conditional rendering submits form data before handleSubmit function

I have a form that upon completion renders a button with form data.
The form takes two inputs: 1. Title (text rendered in button) & 2.) URL for the button.
The form works with the conditional statement if I paste in a URL. However if I begin manually typing a URL, it generates the button based on the first character I type because the string is no longer empty.
export default class URLButton extends Component {
constructor(props) {
super(props)
this.state = {
links: [],
url: '',
title: ''
}
}
// onChange
onChange = (e) => {
e.preventDefault(e)
this.setState({
[e.target.name]: e.target.value
})
}
// onSubmit
onSubmit = e => {
e.preventDefault()
}
render() {
if (this.state.url === "") {
return (
<>
<form onClick={this.onSubmit}>
<input
name="title"
type="text"
placeholder="add button text"
onChange={e => this.setState({ title: e.target.value })}
/>
<input
name="url"
type="url"
placeholder="your-link.com"
onChange={e => this.setState({ url: e.target.value })}
/>
<br />
</form>
<button type="submit">Submit</button>
</>
)
} else {
return (
<>
<div>
{this.state.title}
</div >
</>
)
}
}
}
Since the onChange and onSubmit function works, I've narrowed it down to the conditional statement if (this.state.url === "") {... I've tried setting it to null and false instead of an empty string but the form doesn't render if I try those statements.
Yeah, you're right, your problem is that, when you typed something, the url state is not empty anymore, you'll have to validate that the url is valid in order to submit the form, I've made a StackBlitz with the solution of the problem, I hope this helps.
If you want to finish typing and than generate the button
you can change your onChange to onBlur as
<input
name="url"
type="url"
placeholder="your-link.com"
onBlur={e => this.setState({ url: e.target.value })}
/>
Now when you type out and blur out of input than button will be gernerated
Hope it helps
First of all you should pass yours input states to input:
...
<input
name="url"
type="url"
value={this.state.url} // here
placeholder="your-link.com"
onChange={e => this.setState({ url: e.target.value })}
/>
...
By this edit onChange would pass to set state not only character you've just wrote, but all of previous charecters plus last one.
Then look at your code here:
...
if (this.state.url === "")
...
It would be false right after the FISRT charecter in state.url setted.
If you need to check for correct URL you should use regexp in if condition, to check if state.url looks like correct url by your expectations and ONLY after that render the other part of component.

Displaying from JSON stored in state

I'm trying to access an API and pull out information to use in my application. Right now, I'm fetching the data I want to use from the SWAPI, and the object gets stored in state in the way I want it to. However, I'm not able to display the JSON from the saved state. Im sure this is easy, but I haven't been able to figure it out. Here is my code:
import React, { Component } from 'react';
const APIQuery = 'https://swapi.co/api/';
class Searchbutton extends Component {
constructor(props) {
super(props);
this.state = { value: 'planets/1', data: [] };
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
/*Funcionality to handle form and state of form*/
/* Changes state of value whenever the form is changed, in realtime. */
handleChange(event) {
this.setState({ value: event.target.value });
}
/* Prevents default formsubmit for now, and logs the state that is saved.*/
handleSubmit(event) {
console.log('Be with you, and this was written:' + this.state.data);
event.preventDefault();
}
handleJson(json) {
JSON.stringify(this.state.data);
}
/*Lifecycle method that fetches from API*/
componentDidMount() {
fetch(APIQuery + this.state.value)
.then(response => response.json())
.then(data => this.setState({ data }));
}
render() {
return (
<div className="search_wrapper">
<form onSubmit={this.handleSubmit}>
<label>
Search:
<input
type="text"
className="search_bar"
value={this.state.value}
onChange={this.handleChange}
/>
</label>
<input type="submit" value="May the Force" />
</form>
{this.state.data}
json goes here
</div>
);
}
}
You need to stringify the data before you show it.
You have a method that does that although it does not return anything and you also never call it.
So you could change it to
handleJson(json) {
return JSON.stringify(this.state.data); // added the return statement
}
and then when you want to display it use
{this.handleJson()}
json goes here
Or you could directly stringify before showing it
{JSON.stringify(this.state.data)}
json goes here
You can use
<pre>{JSON.stringify(this.state.data)}</pre>
Here is an example of it: https://stackblitz.com/edit/react-y8bk6f
One of the good alternate solution I found is this:
https://stackoverflow.com/a/35340052/2630817
Changes to your render method
return (
<div className="search_wrapper">
<form onSubmit={this.handleSubmit}>
<label>
Search:
<input
type="text"
className="search_bar"
value={this.state.value}
onChange={this.handleChange}
/>
</label>
<input type="submit" value="May the Force" />
</form>
<pre>{JSON.stringify(this.state.data)}</pre>
json goes here
</div>
);

Efficient way to init state storage of forms

I'm working on a quite comprehensive form and was wondering if there is a smart way to prevent me of doing the following state initialisation:
class Demo extends React.Component {
state = { firstName = "",
secondName = "" };
//and so on...
render() {
const { firstName, secondName } = this.state;
//and so on
return (
<div>
<Form>
<Form.Input
placeholder="Name"
name="name"
value={firstName}
/>
//and so on
</Form>
</div>
);
}
}
If I don't init the state with empty strings I get the following Warning:
Component is changing an uncontrolled input of type text to be
controlled. Input elements should not switch from uncontrolled to
controlled (or vice versa). Decide between using a controlled or
uncontrolled input element for the lifetime of the component.
What's the state of the art way to deal with this?
Thanks!
Stefan
If you are using value as your state value then it will be undefined in render method in case you don't initialize state. So it is recommended to initialize your state like you're doing because you have controlled inputs. I believe this would help your case
Something like this should work but problem is you need input handlers for each fields which is cumbersome if you have huge form.
class Demo extends React.Component {
constructor(props) {
super(props)
this.state = {
firstName: '',
lastName: '',
submitted: false
};
}
handleFirstName = (e) => {
this.setState({firstName: e.target.value});
}
handleLastName = (e) => {
this.setState({lastName: e.target.value});
}
handleSubmit(e) {
e.preventDefault();
this.setState({ submitted: true });
const payload = [{this.state.firstName, this.state.lastName}];
this.props.saveData(payload);
}
render() {
return(
<form>
<label>
Firstname:
<input type="text" value={this.state.firstName} onChange={this.handleFirstName} />
</label>
<label>
Lastname:
<input type="text" value={this.state.lastName} onChange={this.handleLastName} />
</label>
<input type="submit" value="Submit" onClick={this.handleSubmit} />
</form>
);
}
}
Better solution for handling form is using lib like react-final-form

React how to set a default value

Hello I'm new to react and redux. What I'm trying to do is have an edit page that gets the value from my server and puts it in an input value so the user can edit the value.
<FormGroup>
<Label htmlFor="name">Name *</Label>
<div className="controls">
<InputGroup>
<Input id="name" size="16" type="text" value={this.props.user.name} />
</InputGroup>
</div>
</FormGroup>
Inside a react component.
constructor(props) {
super(props)
this.handleSubmit = this.handleSubmit.bind(this)
this.componentWillMount = this.componentWillMount.bind(this)
}
componentWillMount(){
// this will return my current user
this.props.dispatch(fetchUser())
console.log(this.props.user.name) //outputs 'John'
}
How can i insert the username inside the input. I tried using the id and all the traditional javascript ways but its not working.
It looks like used a react-bootstrap.
Below sample use defaultValue property.
if you want to handle input value by
<FormControl
type="text"
autoFocus
onBlur={this.handleMessage}
defaultValue={this.props.user.name}
/>
handlers...
handleMessage = (event) => {
this.setState({
userName: event.target.value,
});
// or do action
// this.props.dispatch(notifyAction.changeUserName(event.target.value));
};

Populate input form field in a div on button click in React Js

I have to show the input text value that user enters in the input form field below the text box on a button click in reactjs.
I have created the function out of the render function and is returning the value and calling that function on button click but it is not working for me. I am not getting the value on button click which i am writing in textbox on the same page.
Whats the solution for this?
here i have created the function to set my nput state
here i have to return the state on button click in expression
Is this what you want?
class Test extends React.Component {
constructor(props){
super(props);
this.state = {
values: {},
showValues: {}
}
}
handleChange(name, e){
let values = this.state.values;
values[name] = e.target.value;
this.setState({values: values})
}
handleClick(e){
let inputValues = this.state.values;
this.setState({showValues: inputValues});
}
render(){
return (
<div>
<input type="text" value={this.state.values["one"]} onChange={this.handleChange.bind(this, "one")}/>
<p>{this.state.showValues["one"]}</p>
<input type="text" value={this.state.values["two"]} onChange={this.handleChange.bind(this, "two")}/>
<p>{this.state.showValues["two"]}</p>
<input type="text" value={this.state.values["three"]} onChange={this.handleChange.bind(this, "three")}/>
<p>{this.state.showValues["three"]}</p>
<input type="text" value={this.state.values["four"]} onChange={this.handleChange.bind(this, "four")}/>
<p>{this.state.showValues["four"]}</p>
<button onClick={this.handleClick.bind(this)}>Show value</button>
</div>
)
}
}
React.render(<Test />, document.getElementById('container'));
Here is updated jsfiddle.

Resources