I am trying to create a way for a user to multiply their form.
A user may add several "Name"/"Number" at one time. But they will only add it under one "Area"
How do I create a form where I can "duplicate" the input fields?
It will, in a way, simply "copy" the form so you can enter the data again.
This screenshot should explain:
I've also put it in a code pen:
http://codepen.io/yarnball/pen/qaQomG?editors=1010
var Postapi = React.createClass({
getInitialState: function() {
return {
area:'',
name: '',
number: '',
};
},
onChange(e) {
this.setState({[e.target.name]: e.target.value})
},
handleSubmit: function(e) {
e.preventDefault();
return fetch('http://localhost:8000/api/Data/', {
method: 'POST',
body: JSON.stringify({
area: this.state.area,
info:[
{name:this.state.name,
taglevel:this.state.number}
],
})
})
.then(function(res){ return res.json(); })
.then(function(data){ alert( JSON.stringify( data ) ) })
},
render: function() {
return (
<form onSubmit={this.handleSubmit}>
<input
name="area"
type="text"
placeholder="Area"
onChange={this.onChange}
/>
<input
name="name"
type="text"
placeholder="Name"
onChange={this.onChange}
/>
<input
name="number"
type="text"
placeholder="Number"
onChange={this.onChange}
/>
<button type="submit">Submit</button>
</form>
);
}
});
Working pen: http://codepen.io/pranesh-r/pen/qagmxX?editors=1010
You need state to maintain the number of input block to be displayed. When the user clicks add more, increment the state and render the n number of input blocks. This solves your first problem.
Handler
addMore(){
this.setState({
formItems: this.state.formItems + 1
})
},
HTML
<button type="button" onClick={this.addMore}>Add More</button>
Dynamic content
const fi = <div>
<input
name="name"
type="text"
placeholder="Name"
onChange={this.onChange}
/>
<input
name="number"
type="text"
placeholder="Number"
onChange={this.onChange}
/>
</div>
const formItem = [];
for (var i= 0; i< this.state.formItems; i++){
formItem.push(fi)
}
Use the formItem in the render.
To serialize the form, I've used jQuery .serialize(). If you don't wanna use jQuery you need to maintain the values of the input in the state for the each inputs. And during submit, get the value from the state and pass it to the server. This solves your second problem.
Hope this helps!
Related
I currently have a working hook, that checks the onChange of input fields, then spreads (I think that is the term for ...) them into a variable and send's them to a Lamda function to send a email with sendgrid. All of that is working.
However if I add a input type of checkbox I am a little lost on the logic side. Because I am checking for the target's name and pairing that with it's value. Well the checkbox has a checked state not a value.
I assume I have to do something like e.target.checked in my setFormState however how do I do that as well as the e.target.value and still spread it to ...formState?
I am a react noob.
Here is my react state and the change event and submit event
const [formState, setFormState] = React.useState({
name: "",
package: `${data.datoCmsPricing.title}`,
email: "",
subject: "",
weightLoss:"",
message: "",
})
const onChange = (e) => {
setFormState({...formState, [e.target.name]: e.target.value });
}
const submitForm = async (e) => {
e.preventDefault();
console.log("test");
try{
const response = await fetch("/.netlify/functions/sendmail", {
method: "POST",
body: JSON.stringify(formState),
})
if (!response.ok) {
console.log(response);
return
}
console.log("success email");
} catch(e){
console.log("error");
}
}
Here is my form code
<form onSubmit={submitForm}>
<label>
Name
<input
type="text"
name="name"
value={formState.name}
onChange={onChange}
/>
</label>
<label>
Email
<input
type="email"
name="email"
value={formState.email}
onChange={onChange}
/>
</label>
<label>
Subject
<input
type="text"
name="subject"
value={formState.subject}
onChange={onChange}
/>
</label>
<div>
<h3>Reasons for wanting to train</h3>
<label>
Weight Loss
<input
type="checkbox"
name="weightLoss"
checked={formState.weightLoss}
onChange={onChange}
/>
</label>
</div>
<label>
message
<textarea
name="message"
value={formState.message}
onChange={onChange}
/>
</label>
<button type="submit">Submit</button>
</form>
In your change handler, detect if it's a checkbox that is not checked, then set the state accordingly:
if (e.target.type === 'checkbox' && !e.target.checked) {
setFormState({...formState, [e.target.name]: ''});
} else {
setFormState({...formState, [e.target.name]: e.target.value });
}
I want create a function using with i can reset value in form inputs without submit. I tried create that function in App Component (resetFormFields) and pass it on props to Form Component. It's preety simply when I want to do this onSubmit (e.target.reset()) but I got stuck when I have to do it without submit, on a different element than the form. Can I do that without adding these values to state?
App:
class App extends Component {
state = {
people: [],
formMessages: [],
person: null
};
handleFormSubmit = e => {
e.preventDefault();
const form = e.target;
const name = form.elements["name"].value;
const username = form.elements["username"].value;
this.addPerson(name, email);
form.reset();
};
resetFormFields = () => {
return;
}
render() {
return (
<div className="App">
<Form formSubmit={this.handleFormSubmit}
reset={this.resetFormFields} />
</div>
);
}
Form:
const Form = props => (
<form className={classes.Form}
id="form"
onSubmit={props.formSubmit}>
<input autoFocus
id="name"
type="text"
defaultValue=""
placeholder="Name..."
/>
<input
id="email"
type="text"
defaultValue=""
placeholder="Email..."
/>
<Button
btnType="Submit"
form="form"
type='submit'>
Submit
</Button>
<label onClick={props.reset}>Reset fields</label>
</form> );
onHandleFormSubmit = (e) =>{
e.preventDefault();
e.target.reset();
}
You need to make your inputs controlled by passing the value you store in your state then you just have to reset the state values and your component value resets.
check this sample below
handleInputChange = (e) => {
let { name, value } = e.target;
this.setState({
...this.state,
inputs: {
[name]: value
}
});
}
your component will now look like
<input name='fullName' value={this.state.inputs.fullName} onChange={this.handleInputChange} />
Your reset function will just clear the state and your input field will be empty since it's controlled via state
resetInputFields = () => {
this.setState({ inputs: {} })
}
you should give set your input values based on component state, then just update the component state
class App extends Component {
state = {
people: [],
formMessages: [],
person: null,
name: "",
email: "",
};
updateState = (newState) => {
this.setState(newState);
}
handleFormSubmit = e => {
e.preventDefault();
this.addPerson(this.state.name, this.state.email);
form.reset();
};
resetFormFields = () => {
this.setState({name:"", email: ""});
}
render() {
return (
<div className="App">
<Form formSubmit={this.handleFormSubmit} updateState={this.updateState}
reset={this.resetFormFields} email={this.state.email} name={this.state.name} />
</div>
);
}
and then
const Form = props => (
<form className={classes.Form}
id="form"
onSubmit={props.formSubmit}>
<input autoFocus
id="name"
type="text"
defaultValue=""
value={this.props.name}
onChange={(e) => this.props.updateState({name: e.target.value})}
placeholder="Name..."
/>
<input
id="email"
type="text"
defaultValue=""
value={this.props.email}
onChange={(e) => this.props.updateState({email: e.target.value})}
placeholder="Email..."
/>
<Button
btnType="Submit"
form="form"
type='submit'>
Submit
</Button>
<label onClick={props.reset}>Reset fields</label>
</form> );
I am building a game in which I want players to be able to add as few as two or as many as four players. Each player has a name and a character.
The class thus far looks like this:
class UserForm extends Component {
constructor(props) {
super(props);
this.state = {
warnings: {},
error: null,
success: null,
name: "",
piece: "",
};
this.submitRequest = this.submitRequest.bind(this);
}
submitRequest(event) {
event.preventDefault();
var content = {
name: this.state.name,
piece: this.state.piece
};
createUser(content)
.then(() => {
return this.setState({
success: "User Added!",
error: null,
warnings: {}
});
})
.catch(err => {
return this.setState({
error: err.message || "An unexpected error occurred",
warnings: {}
});
});
}
addUser(stateName, e,playerNumber) {
this.setState({
[stateName]: e.target.value,
[playerNumber]:playerNumber
});
}
render() {
var inputFields = (
< div >
<label>
Name:
<input type="text" onChange={e => this.addUser("name", e)} />
</label>
<br />
<label>
Piece:
<input type="text" onChange={e => this.addUser("piece", e)} />
</label>
</div >
);
return (
<div>
<form onSubmit={this.submitRequest}>
<label>
Player 1
</label>
<br />
{inputFields}
Player 2
<br />
{inputFields}
Player 3
<br />
{inputFields}
Player 4
<br />
{inputFields}
<input type="submit" value="Submit" />
</form>
<div className="alert alert-danger mt-2" role="alert">
{this.state.error}
{this.state.success}
</div>
</div >
);
}
}
export default UserForm;
I want all the players to be added to my database when one submit button is pressed. But the data is essentially the same in each case. I've been fiddling around with this by using for loops, etc. for a while but it doesn't seem quite right. Grateful for any help!
Thanks,
First thing
You are passing only two Parameters I.e, name, event to addUser function from input field but in addUser you are trying to access three parameters
addUser(stateName, e,playerNumber) //this is wrong
addUser(stateName, e) //this is correct
Then as you mentioned you want to submit all players info in one submit in this case you need three states
this.state= {
name:””,
piece:””,
userData: []
}
So whenever addUser is called then push player information to a state array and finally send that array when form is submitted. You can iterate list of players info in the backend while constructing a query.
Also when you assign value to name and piece state you have to pass these states as a value to an input field otherwise you won’t get value
<input type=“text” value={this.state.name} onChange={e => this.addUser(“name”, e)} />
Here we have to write three functions to change the state of all input fields of form and in case if we have more fields e.g phone and address we have to write two more functions to change the state of those fields, i want to ask is there any way we can write only a single generic function to change the state of any field of this form rather than write separate function for every form field?
class SignUpForm extends React.Component {
constructor() {
super();
this.state = {
name: '',
email: '',
password: '',
};
}
handleNameChange = (evt) => {
this.setState({name: evt.target.value});
}
handleEmailChange = (evt) => {
this.setState({email: evt.target.value});
}
handlePasswordChange = (evt) => {
this.setState({password: evt.target.value});
}
render(){
return(
<form onSubmit={this.handleSubmit}>
<input
type="text"
placeholder="Enter Name"
value={this.state.name}
onChange={this.handleNameChange}
/>
<input
type="text"
placeholder="Enter email"
value={this.state.email}
onChange={this.handleEmailChange}
/>
<input
type="password"
placeholder="Enter password"
value={this.state.password}
onChange={this.handlePasswordChange}
/>
<button disabled={isDisabled}>Sign up</button>
</form>
)
}
}
You could use the following pattern:
handleChange = (type, event) => {
this.setState({[type]: event.target.value});
}
You use handleChange like that:
<input
type="text"
placeholder="Enter Name"
value={this.state.name}
onChange={(event) => this.handleChange('name', event)}
/>
There's an even cleaner way to write this using currying:
handleChange = type => event => this.setState({[type]: event.target.value})
<input
type="text"
placeholder="Enter Name"
value={this.state.name}
id="name"
onChange={this.handleChange('name')}
/>
You could even use the element's ID attribute to avoid the instantiation of a new handler every time you render (since this.handleChange('name') would return a new instance of event => this.setState({name: event.target.value}) every render), and to avoid repeating yourself. However this may not be advisable since it means your element IDs must match your state keys.
handleChange = event => this.setState({[event.target.id]: event.target.value})
<input
type="text"
placeholder="Enter Name"
value={this.state.name}
id="name"
onChange={this.handleChange}
/>
I have the following form component in a skylight dialog, after submit, if the dialog is reopened containing the form, it contains the previous submitted value. Can anyone please tell me how to stop this and clear the textarea value everytime the dialog is opened?
Here is my component:
var AddNoteForm = React.createClass({
componentDidMount: function() {
React.findDOMNode(this.refs.notes).value = "";
},
handleSubmit: function (event) {
event.preventDefault();
var notes = React.findDOMNode(this.refs.notes).value;
var details = {
studentId: this.props.studentId,
schoolId: this.props.schoolId,
notes: notes
};
this.props.onSubmit(details);
},
render: function() {
return (
<form className="pure-form pure-form-aligned"
onSubmit={this.handleSubmit}>
<div className="pure-control-group">
<label htmlFor="notes">Note</label>
<textarea ref="notes" id="notes" placeholder="Note..." >
</textarea>
</div>
<div className="pure-controls">
<input type="submit" value="Save" />
</div>
</form>
);
}
});
module.exports = AddNoteForm;
Basically your form is not getting unmounted. So writing the code in componentDidMount will not make sense. So the quick fix for your problem would be to clear the textarea box after you read the value in handle submit method
handleSubmit: function (event) {
event.preventDefault();
var notes = this.refs.notes;
var details = {
studentId: this.props.studentId,
schoolId: this.props.schoolId,
notes: notes.value
};
notes.value = ""; // Unset the value
this.props.onSubmit(details);
},
so if some one stuck in this problem ,
I was using uncontrolled component and it is somehow complex to clear it,
I just change to controlled one and then got it :)
<form onSubmit={e => this.handleSubmit(e)}>
<textarea value={this.state.text} onChange={ e => this.handleChange(e) } />
<button>Submit Comment</button>
</form>
very important to prevent default
handleSubmit = event => {
event.preventDefault();
this.setState({ text: '' });
};