I have react app.
And some form with input, and I want add button and function, when we click we can add new input in our form.
But I don't know? how I can make it. In native js, I can use create element and appendchild in parent block with some class or id. But in react ((
render() {
return (
<div>
<h1>Form</h1>
<form onSubmit = { this.onSubmit } action="/form" method="post">
<div>
<input type="text" value={this.state.first} name="first" autoFocus="autoFocus" onChange={ this.handleInputChange } />
<input type="text" value={this.state.second} name="second" onChange={ this.handleInputChange } />
</div>
<button onClick={this.handleDouble}>Double</button>
<button>Submit</button>
</form>
</div>
);
}
handleDouble(e) {
e.preventDefault();
}
You need to shape your data to produce the result you want in React.
For example, if I were trying to produce the two inputs you have here, my state would look something like this:
this.state = {
inputs: [{
name: 'first',
autoFocus: true,
type: 'text',
value: '1'
}, {
name: 'second',
autoFocus: false,
type: 'text',
value: '2'
}]
};
Then in my render() function, I would do something like this:
render() {
return (
<div>
<h1>Form</h1>
<form onSubmit = { this.onSubmit } action="/form" method="post">
<div>
{
this.state.inputs.map((input) => (
<input type={input.type} value={input.value} name={input.name} autoFocus={input.autoFocus} onChange={this.handleInputOnChange} />
);
}
</div>
<button onClick={this.handleDouble}>Double</button>
<button>Submit</button>
</form>
</div>
);
}
This would produce 1 input for each index of this.state.inputs.
Related
In an example of a Vue wizard form I tried to add form validation with Joi. How do I set this up logically? The goal is to controll the fields before moving to the second and last page with the next() method. Because of the simplicity of this wizard form, I don't want to change to VueFormWizard. To increase the code I erased a lot of fields etc..
<template>
<div>
<div v-if="errorMessage" class="alert alert-danger" role="alert">
{{errorMessage}}
</div>
<form>
<div v-if="step ===1 ">
<div class="form-group">
<label for="title">Title</label>
<input v-model="example.title"
type="text"
class="form-control"
id="title" />
</div>
<button #click.prevent="next()">Next step</button>
</div>
<div v-if="step === 2">
<div class="form-group">
<label for="userName">Email.</label>
<input v-model="example.userName"
type="email"
class="form-control"
id="userName" />
</div>
<button #click.prevent="prev()">Go back</button>
<button #click.prevent="createExample" type="submit" class="btn btn-primary">Submit</button>
</div>
</form>
</div>
</template>
<script>
import Joi from 'joi'
const schema = Joi.object().keys({
title: Joi.string().alphanum().min(2).max(40).required(),
userName: Joi.string().email(),
})
export default {
data: () => ({
step: 1,
errorMessage: false,
example: {
title: '',
userName: ''
}
}),
watch: {
example: {
handler () {
this.errorMessage = ''
},
deep: true
}
},
methods: {
prev () {
this.step--
},
next () {
this.step++
if (this.validUser()) {
return false
}
},
createExample () {
// Post request
},
validUser () {
const result = Joi.validate(this.huismap, schema)
return true
if (result.error.message.includes('title')) {
this.errorMessage = 'Vul een titel in van min 2 karakters'
return false
}
}
}
</script>
You can make use of browser validation if you set it up like this:
<form #submit.prevent="submitMyForm">
<input v-model="form.title" required minlength="4" maxlength="20" />
<button type="submit">Submit</button>
</form>
Now your browser will prevent you from submitting the form if title is empty, if the length is less than 4 or greater than 20.
This solution can do a lot of stuff, even regex checking:
https://developer.mozilla.org/en-US/docs/Learn/HTML/Forms/Form_validation#Validating_against_a_regular_expression
However this is limited to a small set of checks and is not supported by older browsers. If you need very specific validation you'd have to use a custom solution, which is described here https://v2.vuejs.org/v2/cookbook/form-validation.html.
I need to implement a clear/reset for the inputs after onClick occurs, and also after it is stored in localStorage. I can't seem to figure out how to code this and where. Here is my add function and render function.
addExpense(e) {
e.preventDefault()
let exList = this.state.exList
if (this.state.expense === null) {
alert('Please enter a name.')
return false
}
if (this.state.amount === 0) {
alert('Please enter a valid amount.')
return false
}
if(isNaN(this.state.amount)) {
alert('The amount must be a number.')
return false
}
this.state.exList.push({ 'title':this.state.title, 'amount':this.state.amount })
this.setState({ exList: this.state.exList })
localStorage.setItem('exList', JSON.stringify(exList))
}
render() {
let myExpenses = this.state.exList.map((val, key) => { return <ExpenseList val={val} key={key} id={key} delMe={() =>this.removeExpense(key) } />
})
return (
<main className="ContactList">
<section className="add container">
<h2 className="newExpense">Add Expense</h2>
<form name="myForm">
<p>
<label>Title </label>
<input type="text" name="title" onChange= .
{this.changeExpense} />
<label>Amount </label>
<input type="text" name="amount" onChange= .
{this.changeAmount} />
<button type="submit" className="btn" onClick= .
{this.addExpense}>Add</button>
</p>
</form>
</section>
<section className="container">
<h3 className="currentExpense">Current Expenses</h3>
<article className="contentScroll">
<ul className="expenseCont">{myExpenses}</ul>
</article>
</section>
</main>
)
}
In react everything depends on your state, If the value of a state field changed then your page again render by react
So if you want to clear all the fields of your form then you have to clear the object associated with your text.
Like I set an object in the state within the construction of a component like
this.setState({name: '', email: '', phone_number: ''});
Now after some operation, all the field in my state has values. Now I want clear all the fields after click a button clear, then I will make a function for the clear button and I will write following code inside the clear function
const clear_obj = Object.assign({},this.state);
for(let key in clear_obj){
clear_obj[key] = '';
}
this.setState(clear_obj);
I can also set the default values so that It will look fresh form.
You need to have the value attribute for inputs
value={this.state.expense}
and
value={this.state.amount}
in changeExpense and changeAmount you need to set the state with new value.
to clear inputs, in addExpense below localStorage call you need to setState again
this.setState({ expense: '', amount: '' })
Your code would look like this.
addExpense(e) {
e.preventDefault()
let exList = this.state.exList
if (this.state.expense === null) {
alert('Please enter a name.')
return false
}
if (this.state.amount === 0) {
alert('Please enter a valid amount.')
return false
}
if(isNaN(this.state.amount)) {
alert('The amount must be a number.')
return false
}
this.state.exList.push({ 'title':this.state.title, 'amount':this.state.amount })
localStorage.setItem('exList', JSON.stringify(exList))
this.setState({ expense: '', amount: '', exList: this.state.exList });
}
render() {
let myExpenses = this.state.exList.map((val, key) => { return <ExpenseList val={val} key={key} id={key} delMe={() =>this.removeExpense(key) } />
})
return (
<main className="ContactList">
<section className="add container">
<h2 className="newExpense">Add Expense</h2>
<form name="myForm">
<p>
<label>Title </label>
<input type="text" name="title" value={this.state.expense} onChange= .
{this.changeExpense} />
<label>Amount </label>
<input type="text" name="amount" value={this.state.amount} onChange= .
{this.changeAmount} />
<button type="submit" className="btn" onClick= .
{this.addExpense}>Add</button>
</p>
</form>
</section>
<section className="container">
<h3 className="currentExpense">Current Expenses</h3>
<article className="contentScroll">
<ul className="expenseCont">{myExpenses}</ul>
</article>
</section>
</main>
)
}
If you're just trying to clear some form fields, you could set the state for each field after submission to ''.
For example:
this.setState({
amount: '',
exList: ''
});
You would add this after all of your data has been saved and processed, so at the end of your function would be ok. Or, you could create another function to handle clearing each form field.
Please check this code :
I have a ref attribute in my render template and I would like to play with him for some actions, but for test I just console.log of him but he didn't worked
If you see on my code the focusTextInputmethod, I made a simply console.log of ref value.
export default class Form extends Component {
constructor() {
super();
this._createBounds();
}
_createBounds() {
['focusTextInput']
.forEach((fn) => this[fn] = this[fn].bind(this));
}
static _getSkills() {
return [
{_id: 1, text: 'HTML'},
{_id: 2, text: 'CSS'},
{_id: 3, text: 'JavaScript'},
{_id: 4, text: 'PHP'},
{_id: 5, text: 'MYSQL'}
];
}
_renderSkills() {
return Form._getSkills().map((skills) => (
<Skills key={skills._id} content={skills.text}/>
));
}
/* THIS FUNCTION IS CALL WHEN ONCLICK IF FIRED */
focusTextInput() {
let val = this.refs.newText.value;
console.log(val)
}
/* END */
render() {
return (
<div className="header-form">
<h2 className="header-form-title">Hello, please type informations about you</h2>
<form className="form-container" action="#">
<div className="form-field">
<Input ref="newText" type='text' placeholder="Votre nom"/>
</div>
<div className="form-field">
<Input type='text' placeholder="Votre prénom"/>
</div>
<div className="form-field">
<Input type='text' placeholder="Votre âge"/>
</div>
<div className="form-field">
<Input type='text' placeholder="Votre email"/>
</div>
<div className="form-field">
<select className="form-field-select">
{this._renderSkills()}
</select>
</div>
<div className="form-field submit">
<Input onClick={this.focusTextInput} type='submit' value="Envoyer"/>
</div>
</form>
</div>
)
}
}
When I render an input element within my component if i set the element "value" it become read-only but if i set the value on "defaultValue" it will never update again when i re-update my state.
Here is my code :
import React from "react";
export default class EditForm extends React.Component {
editTransaction(event) {
var transaction = this.props.transaction;
event.preventDefault();
var NewTransaction = {
transactions_data: {
amount: this.refs.amount.value
}
}
this.props.editTransaction(NewTransaction, transaction.id);
}
closeForm() {
this.props.closeForm();
}
render() {
var {amount}=this.props.transaction;
return (
<div>
<br/>
<h4>Edit Transaction</h4>
<div className="btn btn-danger pull-right" onClick={this.closeForm.bind(this)}>close</div>
<div className="clearfix"></div>
<form onSubmit={this.editTransaction.bind(this)}>
<div>
<label for="amount">Amount</label>
<input value={amount} onChange={(value) => this.onChange(value)} className="form-control"
id="amount" name="amount" type="number"
ref="amount"/>
</div>
<br/>
<br/>
<input className="btn btn-info" type="submit" value="submit"/>
</form>
</div>
);
}
}
and then i found out if i make an error out of this by adding
onChange={(value) => this.onChange(value)} on my input element, it works properly ( it updating while the props or state is updating, and i can re-type the value), but i think this is not a proper solution, because it cause errors on my browser console. It is because "this.onChange" function does not exist.
How can this problem be solved?
The reason your input doesn't work is because you need to define the onChange function which actually sets the state with the updated value. You can probably do it inline since it only needs on statement like
<input type="text" value={this.state.inputVal} onChange={(e) => {this.setState({inputVal: e.target.value})}} />
However I would recommend you to use an onChange method as you can handle multiple inputs together with it and it looks cleaner
class EditForm extends React.Component {
constructor() {
super();
this.state = {
}
}
onChange(e) {
this.setState({[e.target.name]: e.target.value})
}
editTransaction(event) {
var transaction = this.props.transaction;
event.preventDefault();
var NewTransaction = {
transactions_data: {
amount: this.refs.amount.value
}
}
this.props.editTransaction(NewTransaction, transaction.id);
}
closeForm() {
this.props.closeForm();
}
render() {
return (
<div>
<br/>
<h4>Edit Transaction</h4>
<div className="btn btn-danger pull-right" onClick={this.closeForm.bind(this)}>close</div>
<div className="clearfix"></div>
<form onSubmit={this.editTransaction.bind(this)}>
<div>
<label for="amount">Amount</label>
<input value={this.state.amount} onChange={(value) => this.onChange(value)} className="form-control"
id="amount" name="amount" type="number"
ref="amount"/>
<input value={this.state.amount1} onChange={(value) => this.onChange(value)} className="form-control"
id="amount1" name="amount1" type="number"
ref="amount"/>
</div>
<br/>
<br/>
<input className="btn btn-info" type="submit" value="submit"/>
</form>
</div>
);
}
}
ReactDOM.render(<EditForm/>, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.2/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.2/react-dom.min.js"></script>
<div id="app"></div>
You need to define an onChange method, if you are using redux that could be an action that updates your component state via a reducer. An easier method using simple state with es6 is shown below. Furthermore, you are getting the value from the input field via ref which is discouraged by Facebook. This should also give you an error because you are trying to control and uncontrolled component.
Here's a link to the form documentation for further reading.
class Foo extends React.Component {
constructor(props) {
super(props);
this.state = ({
inputVal: '',
});
}
onChange = (e) => {
this.setState({ [e.target.name]: e.target.value });
}
handleSubmit = (event) => {
event.preventDefault();
console.log(this.state.inputVal);
}
render() {
return (
<div>
<input type="text" value={this.state.inputVal} onChange={this.onChange} />
</div>
);
}
}
I was tinkering with this and found a really simple solution:
class App extends Component {
constructor(props) {
super(props)
this.enterText = this.enterText.bind(this)
this.state = {
userNameText: 'user name',
pswdText: 'pswd',
textEntry: false
}
}
async enterText() {
if (!this.state.textEntry) {
await this.clearText()
this.setState({textEntry: true})
}
}
clearText() {
this.setState({
userNameText: '',
pswdText: ''
})
}
render() {
return (
<div className="App">
<div className="App-header">
<h1 className="App-title">
Welcome
</h1>
</div>
<div className="login-fields">
<LoginFields userNameText={this.state.userNameText} pswdText={this.state.pswdText} onFocus={this.enterText} />
</div>
</div>
)
}
}
So, upon initial render(), the state of the fields are whatever is hard coded in the constructor. When the user clicks in either the name or pswd box (these could easily be separated), both are cleared with clearText() and then both are set to null with allowText(). Once set to null, the user input text is accepted.
Make sure the LoginFields component has this in the input:
onFocus={this.props.onFocus}
When you set the value on an input in React, its value will never change (unless you specify an onChange handler)
<input type="text" name="address" value="Europe" />
The end result of this element is a textbox with the value Europe that cannot be changed, so effectively, it's a read-only textbox.
Instead, when you want to provide a default value for your input field, you should use the defaultValue attribute as follows:
<input type="text" name="address" defaultValue="Europe" />
So just replace the value attribute with defaultValue
I am currently hacking around with a small front-end react project that is hitting Soundcloud's API. Very basic as of right now, I'm just taking in some user input and querying the api endpoint for related songs. For some strange reason I cannot get the enter key to submit my form and thus fire my this.handleSubmit() method. The only way I can get it to fire is to click the button my enter functionality seems to be broken. I searched around and can't find what I'm overlooking, any assistance is greatly appreciated!
import React from 'react';
import Styles from '../styles/index.js'
class SearchBar extends React.Component {
constructor(props) {
super(props);
this.initPlayer(this.props.song)
};
initPlayer(song){
SC.oEmbed(song, { auto_play: true }).then(function(song) {
document.getElementById('player').innerHTML = song.html;
});
}
handleSubmit(e){
e.preventDefault();
let term = document.getElementById('search').value
SC.get('/tracks', {
q: term
})
.then( (tracks) => {
const song = tracks[0].permalink_url;
if (tracks.length < 1) {
alert('not found!');
}
SC.oEmbed(song, { auto_play: true }).then(function(song) {
document.getElementById('player').innerHTML = song.html;
});
document.getElementById('search').value = '';
});
}
render() {
return (
<div>
<div className="col-lg-12">
<div style={Styles.playerStyle} id="player"></div>
<label htmlFor="search">Artist:</label>
<input type="text" className="form-control" id="search" />
<div className="text-center">
<form onSubmit={this.handleSubmit}>
<button type='submit' style={Styles.buttonStyle} className="btn btn-primary">Submit</button>
</form>
</div>
<div id="player"></div>
<br />
</div>
</div>
);
}
}
export default SearchBar;
form can only be submitted by enter-key when it is focus and has input|button(type="submit"). So just move input into your form.
<form onSubmit={this.handleSubmit}>
<input type="text" className="form-control" id="search" />
<button type='submit' style={Styles.buttonStyle} className="btn btn-primary">Submit</button>
</form>