I entered some data in textbox and after that I clicked on the Button.
After clicked on the button The data should be reset.
class Header extends Component {
constructor(props) {
super(props)
this.state = {
title: 'React App',
keywords: 'Type Above'
}
}
inputData = (event) => {
console.log(event.target.value)
this.setState({ keywords: event.target.value ? event.target.value : 'Type Above' })
}
handleSubmit = (event) => {
event.preventDefault();
alert('Button Clicked');
this.setState({ keywords: "" });
}
render() {
return (
<div>
<h2>{this.state.title}</h2>
<form onSubmit ={this.handleSubmit}>
<center>
<input type="text"
placeholder="Search Value..."
onChange ={this.inputData} />
<h3>{this.state.keywords}</h3>
</center>
<button> BUtton </button>
</form>
</div>
)
}
}
Data should get reset after button is clicked...
You need to provide value prop to your input,
<input type="text"
placeholder="Search Value..."
onChange ={this.inputData}
value = {this.state.keywords}
/>
Lear more about Controlled Component.
Demo
class Header extends Component {
constructor(props) {
super(props);
this.state = {
title: "React App",
keywords: "Type Above"
};
}
inputData = event => {
console.log(event.target.value);
this.setState({
keywords: event.target.value ? event.target.value : "Type Above"
});
};
handleSubmit = event => {
event.preventDefault();
alert("Button Clicked");
this.setState({ keywords: "" });
};
render() {
return (
<div>
<h2>{this.state.title}</h2>
<form onSubmit={this.handleSubmit}>
<center>
<input
type="text"
placeholder="Search Value..."
value={this.state.keywords === 'Type Above' ? '' : this.state.keywords}
onChange={this.inputData}
/>
<h3>{this.state.keywords}</h3>
</center>
<button> BUtton </button>
</form>
</div>
);
}
}
your problem is that you didn't assign the keywords value to the input, because the value is correctly deleted after you click the button, you can see it here:
class Header extends Component {
state = {
title : 'React App',
keywords : 'Type Above'
};
inputData = event => {
console.log(event.target.value)
this.setState({ keywords: event.target.value ? event.target.value : 'Type Above' });
};
handleSubmit = event => {
event.preventDefault();
alert('Button Clicked');
this.setState({ keywords: "" });
};
render() {
const { keywords, title } = this.state;
return (
<div>
<h2>{title}</h2>
<form onSubmit={this.handleSubmit}>
<center>
<input
type="text"
placeholder="Search Value..."
onChange={this.inputData}
value={keywords}
/>
<h3>{keywords}</h3>
</center>
<button>Button </button>
</form>
</div>
)
}
}
Hope this helps, Regards.
You are missing value attribute for your input. You need to add something like this value={this.state.keywords}
Related
the below code works fine, but it has a small issue, it did not clean an input field value when I click the button, so I have tried to put a code this.setState({ name: ''}) into nameChangedHandler that make this input value back to empty, but it does not work and will lock the input value to empty, and then you could not type any data into this input value.
Does it work by using Component Lifecycle?
class AddPerson extends Component {
state = {
name: '',
age: '',
};
nameChangedHandler = event => {
this.setState({ name: event.target.value });
};
ageChangedHandler = event => {
this.setState({ age: event.target.value });
};
render() {
return (
<div className="AddPerson">
<input
type="text"
placeholder="Name"
onChange={this.nameChangedHandler}
value={this.state.name}
/>
<input
type="number"
placeholder="Age"
onChange={this.ageChangedHandler}
value={this.state.age}
/>
<button onClick={() => this.props.personAdded(this.state.name, this.state.age)}>
Add Person
</button>
</div>
);
}
}
export default AddPerson;
You clean the name in the button's onClick handler:
<button onClick={() => {
this.props.personAdded(this.state.name, this.state.age);
this.setState({ name: '' });
}}>
Add Person
</button>
class AddPerson extends React.Component {
constructor(props) {
super(props);
this.state = {
name: "",
age: ""
};
}
nameChangedHandler = (event) => {
this.setState({ name: event.target.value });
};
ageChangedHandler = (event) => {
this.setState({ age: event.target.value });
};
handleSubmit = () => {
this.props.personAdded(this.state.name, this.state.age);
this.setState({
name: "",
age: ""
});
};
render() {
return (
<div className="AddPerson">
<input
type="text"
placeholder="Name"
onChange={this.nameChangedHandler}
value={this.state.name}
/>
<input
type="number"
placeholder="Age"
onChange={this.ageChangedHandler}
value={this.state.age}
/>
<button onClick={this.handleSubmit}>Add Person</button>
</div>
);
}
}
export default AddPerson;
EDIT
Sorry for showing wrong use-case. All inputs inside the Form are being passed though this.props.children, and they can be situated at any deep point of the components tree, so the approach of passing the handleChange directly to inputs will not work at all.
Here is code snippet with the reproduction of the problem.
class CustomSelect extends React.Component {
items = [
{ id: 1, text: "Kappa 1" },
{ id: 2, text: "Kappa 2" },
{ id: 3, text: "Kappa 3" }
]
state = {
selected: null,
}
handleSelect = (item) => {
this.setState({ selected: item })
}
render() {
var { selected } = this.state
return (
<div className="custom-select">
<input
name={this.props.name}
required
style={{ display: "none" }} // or type="hidden", whatever
value={selected
? selected.id
: ""
}
onChange={() => {}}
/>
<div>Selected: {selected ? selected.text : "nothing"}</div>
{this.items.map(item => {
return (
<button
key={item.id}
type="button"
onClick={() => this.handleSelect(item)}
>
{item.text}
</button>
)
})}
</div>
)
}
}
class Form extends React.Component {
handleChange = (event) => {
console.log("Form onChange")
}
render() {
return (
<form onChange={this.handleChange}>
{this.props.children}
</form>
)
}
}
ReactDOM.render(
<Form>
<label>This input will trigger form's onChange event</label>
<input />
<CustomSelect name="kappa" />
</Form>,
document.getElementById("__root")
)
<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="__root"></div>
As you can see, when you type something in default input (controlled or uncontrolled, whatever), form catches bubbled onChange event. But when you are setting the value of the input programmatically (with the state, in this case), the onChange event is not being triggered, so I cannot catch this changes inside the form's onChange.
Is there any options to beat this problem? I tried to input.dispatchEvent(new Event("change", { bubbles: true })) immediately after setState({ selected: input }) and inside it's callback, but there is no result.
I really think the best to do what you try to do is first make sure to control each individual input. Keep those values in state and just working with the onSubmit event from the form. React even recommended this approach here https://reactjs.org/docs/uncontrolled-components.html
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.
You can read about controlled here https://reactjs.org/docs/forms.html#controlled-components
If you want to see how I will have made with just control this will have been looks like that https://codesandbox.io/s/2w9qnk8lxp You can see if you click enter the form submit event with the value keep in state.
class CustomSelect extends React.Component {
items = [
{ id: 1, text: "Kappa 1" },
{ id: 2, text: "Kappa 2" },
{ id: 3, text: "Kappa 3" }
];
render() {
return (
<div className="custom-select">
<div>
Selected: {this.props.selected ? this.props.selected.text : "nothing"}
</div>
{this.items.map(item => {
return (
<button
key={item.id}
type="button"
onClick={() => this.props.onChange(item)}
>
{item.text}
</button>
);
})}
</div>
);
}
}
class Form extends React.Component {
state = {
firstInput: "",
selected: null
};
handleSubmit = event => {
event.preventDefault();
console.log("Form submit", this.state);
};
handleInputChange = name => event => {
this.setState({ [name]: event.target.value });
};
handleSelectedChanged = selected => {
this.setState({ selected });
};
render() {
console.log(this.state);
return (
<form onSubmit={this.handleSubmit}>
<label>This input will trigger form's onChange event</label>
<input
value={this.state.firstInput}
onChange={this.handleInputChange("firstInput")}
/>
<CustomSelect
name="kappa"
selected={this.state.selected}
onChange={this.handleSelectedChanged}
/>
</form>
);
}
}
But if you really want your way, you should pass down the handleChange function as a callback to the children and make use of this props as a function when you click on an element. Example here https://codesandbox.io/s/0o8545mn1p.
class CustomSelect extends React.Component {
items = [
{ id: 1, text: "Kappa 1" },
{ id: 2, text: "Kappa 2" },
{ id: 3, text: "Kappa 3" }
];
state = {
selected: null
};
handleSelect = item => {
this.setState({ selected: item });
this.props.onChange({ selected: item });
};
render() {
var { selected } = this.state;
return (
<div className="custom-select">
<input
name={this.props.name}
required
style={{ display: "none" }} // or type="hidden", whatever
value={selected ? selected.id : ""}
onChange={() => {}}
/>
<div>Selected: {selected ? selected.text : "nothing"}</div>
{this.items.map(item => {
return (
<button
key={item.id}
type="button"
onClick={() => this.handleSelect(item)}
>
{item.text}
</button>
);
})}
</div>
);
}
}
class Form extends React.Component {
handleChange = event => {
console.log("Form onChange");
};
render() {
return (
<form onChange={this.handleChange}>
<label>This input will trigger form's onChange event</label>
<input />
<CustomSelect name="kappa" onChange={this.handleChange} />
</form>
);
}
}
If you pass down the function from the form you can trigger it manually. You just need to create the new Event() to suite you needs of info. Since its a prop it will sync if any method changes happen in the parent element.
Since you use props to generate elements within the form you must map them like so. This was the event only gets added to the custom elements.
class CustomSelect extends React.Component {
propTypes: {
onChange: React.PropTypes.func
}
items = [
{ id: 1, text: "Kappa 1" },
{ id: 2, text: "Kappa 2" },
{ id: 3, text: "Kappa 3" }
]
state = {
selected: null,
}
handleSelect = (item) => {
this.setState({ selected: item });
this.props.onChange.self(new Event('onchange'))
};
render() {
var { selected } = this.state
return (
<div className="custom-select">
<input
name={this.props.name}
required
style={{ display: "none" }} // or type="hidden", whatever
value={selected
? selected.id
: ""
}
onChange={() => {}}
/>
<div>Selected: {selected ? selected.text : "nothing"}</div>
{this.items.map(item => {
return (
<button
key={item.id}
type="button"
onClick={() => this.handleSelect(item)}
>
{item.text}
</button>
)
})}
</div>
)
}
}
class Form extends React.Component {
handleChange = (event) => {
console.log("Form onChange")
}
render() {
let self = this.handleChange;
let children = React.Children.map(this.props.children, (child, i) => {
if(typeof child.type === "function"){
return React.cloneElement(child, {
onChange: {self}
});
}
return child;
});
return (
<form onChange={this.handleChange}>
{children}
</form>
)
}
}
ReactDOM.render(
<Form>
<label>This input will trigger form's onChange event</label>
<input />
<CustomSelect name="kappa" />
</Form>,
document.getElementById("__root")
)
<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="__root"></div>
Update your CustomSelect component with the following:
class CustomSelect extends React.Component {
...
// you'll use this reference to access the html input.
ref = React.createRef();
handleSelect = item => {
this.setState({ selected: item });
// React overrides input value setter, but you can call the
// function directly on the input as context
const inputValSetter = Object.getOwnPropertyDescriptor(
window.HTMLInputElement.prototype,
"value"
).set;
inputValSetter.call(this.ref.current, "dummy");
// fire event
const ev = new Event("input", { bubbles: true });
this.ref.current.dispatchEvent(ev);
};
...
render() {
...
return (
<div className="custom-select">
<input
// you'll use the reference in `handleSelect`
ref={this.ref}
name={this.props.name}
required
style={{ display: "none" }} // or type="hidden", whatever
value={selected ? selected.id : ""}
onChange={() => {}}
/>
...
</div>
);
}
...
}
And your Form component with the following:
class Form extends React.Component {
handleChange = event => {
console.log("Form onChange");
// remove synthetic event from pool
event.persist();
};
...
}
I make a simple react app.
I have a React form with field.
And we can add dynamically more and more same fields. And submit them together.
Maybe I can use for or while? But how?
And I must add dynamically fields name in form, and dynamically fields to object for submit.
class Form extends Component {
constructor(props) {
super(props);
this.state = {
task: '',
count: [1]
};
this.addTask = this.addTask.bind(this);
this.change = this.change.bind(this);
}
render() {
return (
<div>
<h1>Form</h1>
<form onSubmit = {this.onSubmit} method='post'>
<div>
{this.state.count.map((item, index) => {
return (
<div key={index}>
<input type='text' value={this.state.task} name='task' onChange={this.change} />
</div>
)
})}
</div>
<button onClick={this.addTask}>addTask</button>
<button>submit</button>
</form>
</div>
);
}
addTask(e) {
e.preventDefault();
this.setState({
count: [...this.state.count, '1']
})
}
onSubmit = (e) => {
e.preventDefault();
const {submit} = this.props;
submit({
task: this.state.task
});
this.setState({
task: ''
})
};
change(event) {
const target = event.target;
const value = target.type === 'checkbox' ? target.checked : target.value;
const name = target.name;
this.setState({
[name]: value
});
}
}
export default connect(null, { submit })(Form);
You can map through an array of your objects:
constructor(props) {
super(props);
this.state = {
task: '',
count: [1],
components: []
};
this.addTask = this.addTask.bind(this);
this.change = this.change.bind(this);
}
render() {
return (
<div>
<h1>Form</h1>
<form onSubmit = {this.onSubmit} method='post'>
<div>
{this.state.count.map((item, index) => {
return (
<div key={index}>
{this.state.components.map(comp => comp)}
</div>
)
})}
</div>
<button onClick={this.addTask}>addTask</button>
<button>submit</button>
</form>
</div>
);
}
addTask(e) {
e.preventDefault();
this.setState({
count: [...this.state.count, '1'],
components: this.state.components.concat(<input type='text' value={this.state.task} name='task' onChange={this.change} key={this.state.count.length + 1} />)
})
}
I'm a newbie to ReactJS and I have made an app where you can submit a name and email. The name and mail should be displayed in a list at the bottom of the page. It is displayed for a short period, but then the constructor gets called and clears the state and the list.
Why is the constructor called after the state change? I thought the constructor only runs once and then the render-method runs after setState() changes the state.
class App extends React.Component {
constructor(props) {
super(props);
console.log("App constructor");
this.state = {
signedUpPeople: []
};
this.signUp = this.signUp.bind(this);
}
signUp(person) {
this.setState({
signedUpPeople: this.state.signedUpPeople.concat(person)
});
}
render() {
return (
<div>
<SignUpForm signUp={this.signUp} />
<SignedUpList list={this.state.signedUpPeople} />
</div>
);
}
}
class SignUpForm extends React.Component {
constructor(props) {
super(props);
console.log("SignUpForm constructor");
this.state = {
name: "",
email: ""
};
this.changeValue = this.changeValue.bind(this);
this.onSubmitForm = this.onSubmitForm.bind(this);
}
changeValue(event) {
const value = event.target.value;
const name = event.target.name;
this.setState({
name: value
});
}
onSubmitForm() {
this.props.signUp(this.state);
this.setState({
name: "",
email: ""
});
}
render() {
console.log("SignUpForm render");
return (
<div>
<h2>Sign up</h2>
<form onSubmit={this.onSubmitForm}>
<label htmlFor="name">Name:</label>
<input id="name" name="name" onChange={this.changeValue} />
<br />
<label htmlFor="email">E-mail:</label>
<input id="email" name="name" onChange={this.changeValue} />
<input type="submit" value="Sign up" />
</form>
</div>
);
}
}
class SignedUpList extends React.Component {
render() {
console.log("SignedUpList render");
return (
<div>
<h2>Already signed up</h2>
<ul>
{this.props.list.map(({ name, email }, index) => (
<li key={index}>
{name}, {email}
</li>
))}
</ul>
</div>
);
}
}
ReactDOM.render(<App />, window.document.getElementById("app"));
See CodePen example
The default behavior of a form with input of type submit is to post back to the server.
<input> elements of type "submit" are rendered as buttons. When the
click event occurs (typically because the user clicked the button),
the user agent attempts to submit the form to the server.
You can pass the event object of the submit handler and use the event.preventDefault method to prevent the form from posting back:
onSubmitForm(e) {
e.preventDefault();
this.props.signUp(this.state);
this.setState({
name: "",
email: ""
});
}
Here is a running snippet of your code:
class App extends React.Component {
constructor(props) {
super(props);
console.log("App constructor");
this.state = {
signedUpPeople: []
};
this.signUp = this.signUp.bind(this);
}
signUp(person) {
this.setState({
signedUpPeople: this.state.signedUpPeople.concat(person)
});
}
render() {
return (
<div>
<SignUpForm signUp={this.signUp} />
<SignedUpList list={this.state.signedUpPeople} />
</div>
);
}
}
class SignUpForm extends React.Component {
constructor(props) {
super(props);
console.log("SignUpForm constructor");
this.state = {
name: "",
email: ""
};
this.changeValue = this.changeValue.bind(this);
this.onSubmitForm = this.onSubmitForm.bind(this);
}
changeValue(event) {
const value = event.target.value;
const name = event.target.name;
this.setState({
name: value
});
}
onSubmitForm(e) {
e.preventDefault();
this.props.signUp(this.state);
this.setState({
name: "",
email: ""
});
}
render() {
//console.log('SignUpForm render');
return (
<div>
<h2>Sign up</h2>
<form onSubmit={this.onSubmitForm}>
<label htmlFor="name">Name:</label>
<input id="name" name="name" onChange={this.changeValue} />
<br />
<label htmlFor="email">E-mail:</label>
<input id="email" name="name" onChange={this.changeValue} />
<input type="submit" value="Sign up" />
</form>
</div>
);
}
}
class SignedUpList extends React.Component {
render() {
//console.log('SignedUpList render');
return (
<div>
<h2>Already signed up</h2>
<ul>
{this.props.list.map(({ name, email }, index) => (
<li key={index}>
{name}, {email}
</li>
))}
</ul>
</div>
);
}
}
ReactDOM.render(<App />, window.document.getElementById("app"));
<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="app">
</div>
onSubmitForm(e) {
e.preventDefault(); // prevent the form from refreshing the page
this.props.signUp(this.state);
this.setState({
name: "",
email: ""
});
}
It is working with your codepen link :)
Have a deep look at this :
React - Preventing Form Submission
or
https://medium.com/#ericclemmons/react-event-preventdefault-78c28c950e46
Thank you all for your help! :-)
e.preventDefault();
Did fix the problem. Thanks!
I have a form which has 3 field. First two fields are email_from and email_subject and the last field is an editor. I have used draftjs for editor. If there is no editor i could enable and disable the submit button but due to the inclusion of the editor i did not know how can i enable the button only when all the fields are filled with no error.
Here is my code.
AdminEditor is the component which has draftjs editor
class EmailTemplate extends React.Component {
state = {
emailSubject: '',
emailFrom: ''
};
handleChange = event =>
this.setState({ [event.target.name]: event.target.value });
handleSubmit = event => {
event.preventDefault();
};
render() {
const { emailSubject, emailFrom } = this.state;
return (
<form onSubmit={this.handleSubmit}>
<FieldGroup
id="formControlsText"
name="emailSubject"
type="text"
label="Email Subject"
placeholder="Enter Email Form"
onChange={this.handleChange}
validationState={emailSubject ? 'success' : 'error'}
required
/>
<FieldGroup
id="formControlsText"
name="emailFrom"
type="email"
label="Email From"
placeholder="Enter Email From"
onChange={this.handleChange}
validationState={emailFrom ? 'success' : 'error'}
required
/>
<AdminEditor />
<Button type="submit">
Submit
</Button>
</form>
);
}
}
export default EmailTemplate;
class AdminEditor extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
editorState: EditorState.createEmpty(),
isEmpty: true
};
}
onEditorStateChange = editorState => {
this.setState({
editorState
});
};
onEditorChange = editorContent => {
this.setState({
editorContent
});
};
handleChange = event =>
this.state.editorState.getCurrentContent().hasText()
? this.setState({ isEmpty: false })
: this.setState({ isEmpty: true });
render() {
const { editorState } = this.state;
return (
<div>
<Editor
editorState={this.state.editorState}
initialContentState={rawContentState}
toolbarClassName="home-toolbar"
wrapperClassName="home-wrapper"
editorClassName="home-editor"
onEditorStateChange={this.onEditorStateChange}
toolbar={{
textAlign: { inDropdown: true },
}}
onContentStateChange={this.onEditorChange}
placeholder="write text here..."
onChange={this.handleChange}
/>
</div>
);
}
}
export default AdminEditor;
Can anyone please help me?
There are many ways to do this, mostly based around passing some callbacks down into the controlled component which updates the state in the parent.
A simple way would be to pass a handler that sets a flag if the editor is empty or not:
class AdminEditor extends React.PureComponent {
...
handleChange = event =>
this.props.setEditorIsEmpty(
this.state.editorState.getCurrentContent().hasText()
);
Then in EmailTemplate:
setEditorIsEmpty(editorIsEmpty) {
this.setState({
editorIsEmpty
});
}
render() {
const { emailSubject, emailFrom } = this.state;
return (
<form onSubmit={this.handleSubmit}>
...
<AdminEditor
setEditorIsEmpty={this.setEditorIsEmpty}
/>
<Button
type="submit"
disabled={!emailSubject || !emailFrom || editorIsEmpty}>
Submit
</Button>
</form>
);
}