class CategoryBox extends Component {
constructor(props) {
super(props);
this.state = {
newCategoryTitle: '',
errorMsg: null,
updateCategoryTitle: '',
};
this.handleCreateCategory = this.handleCreateCategory.bind(this);
this.handleUpdateCategory = this.handleUpdateCategory.bind(this);
}
...
...
handleUpdateCategory(e) {
e.preventDefault();
this.setState({
updateCategoryTitle: ''
});
}
render() {
return (
//...
<form>
<input
type={'text'}
className={styles.tabSmallField}
placeholder={ category.name }
onChange={(e) => { this.setState({ updateCategoryTitle: e.target.value }); }} />
<button type="submit" onClick={this.handleUpdateCategory}>Update</button>
</form>
//...
}
}
I want to clear input text field after pressing the button.
It looks like it enters into "handleUpdateCategory(e)" after pressing the button. But it does not clear the input field above the button.
How can I clear the input text field?
Answer is in comment.
It didn't clear because you never bind the state value to your <input>. Change it like this <input value={this.state.updateCategoryTitle} ...other props... />
Related
I am using react to accept input from the user. And when the user submits I want to get rid of the form and display the user input data.
I am not able to see the user input data on my result page. I have uploaded the screenshots and the code below.
class Form extends React.Component {
constructor(props){
super(props)
this.state = {isFormOn: true, isResult: false , firstname: "", lastname: ""};
this.handleClick = this.handleClick.bind(this);
this.handleChange = this.handleChange.bind(this);
}
handleClick(){
this.setState(state => ({
isFormOn: !state.isFormOn,
isResult: !state.isResult
}));
}
handleChange({ event }) {
this.setState({
[event.target.name]: event.target.value
});
}
render(){
return(
<div>
{ this.state.isFormOn && (
<div>
First name :
<input type="text" name="firstname" onChange={this.handleChange} /><br />
Last name :
<input type="text" name="lastname" onChange={this.handleChange} /><br />
<br />
<button onClick={this.handleClick}>
{this.state.isFormOn ? 'ON' : 'OFF'}
</button>
</div>
)}
{ this.state.isResult && (
<div>
<h4>The name entered is : {this.state.firstname} {this.state.lastname} </h4>
<button onClick={this.handleClick}>
{this.state.isFormOn ? 'ON' : 'OFF'}
</button>
</div>
)}
</div>
);
}
}
ReactDOM.render(
<Form />,
document.getElementById('root')
);
Render form to accept user input
Result of the user entered information
Your event handler (handleChange) is destructuring the event object, and trying to extract a property called event from it, which doesn't exist.
You need to use the event object directly instead:
handleChange(event) {
this.setState({
[event.target.name]: event.target.value
});
}
I am new to Reactjs and trying to change the of value text which is entered by user in textbox, after button click event.
But after button click event I am getting error "TypeError: Cannot read property 'value' of undefined" at handleChange(e) function.Can anyone please help me with whats going wrong here??
Here is the component I am working with :
Constructor(props){
super();
this.state={
typedtext: 'Nothing'
}
};
handleClick(){
this.handleChange(this.state.typedtext)
}
handleChange(e){
this.setState({ typedtext: e.target.value });
}
render(){
return(
<div>
<label> Typed Value is : {this.state.typedtext} </label> <p>
</p>
<label> Type Something here </label>
<input type='text'onChange={(e)=>this.handleChange(e)}
value= {this.state.typedtext}/>
<button onClick={()=>this.handleClick()}> Copy Text </button>
</div>
);
}
}
The problem appears because when you run handleChange in handleClick method you use the value of your state as the argument instead of event object. It is trying to get value property of string.
Your code should look like this:
constructor(props) {
super(props);
this.state = {
typedtext: 'Nothing'
}
};
handleClick(e) {
this.handleChange(e)
}
handleChange(e) {
this.setState({
typedtext: e.target.value
});
}
render() {
return (
<div>
<label> Typed Value is : {this.state.typedtext} </label>
<p></p>
<label> Type Something here </label>
<input type='text'onChange={e => this.handleChange(e)} value={this.state.typedtext}/>
<button onClick={e => this.handleClick(e)}> Copy Text </button>
</div>
);
}
But handleClick will not copy the text. It will just remove it because handleChange will try to get the value of button that doesn't contain any value.
Working code looks like this:
constructor(props) {
super(props);
this.state = {
typedtext: 'Nothing'
}
};
handleChange() {
this.setState({
typedtext: this.input.value
});
}
render() {
return (
<div>
<label> Typed Value is : {this.state.typedtext} </label>
<p></p>
<label> Type Something here </label>
<input type='text'onChange={() => this.handleChange()} value={this.state.typedtext} ref={input => this.input = input}/>
<button onClick={() => this.handleChange()}> Copy Text </button>
</div>
);
}
But you will not be able to see what the button does because while you are typing it already copies the text. :)
Try to add a bind to "this" refering this method on contructor:
this.handleChange = this.handleChange.bind(this)
The entire code on constructor:
constructor(props){
super();
this.state={
typedtext: 'Nothing'
}
this.handleChange = this.handleChange.bind(this)
};
I have a list of students on my page. When I click on some student, a form should appear with input element for all of student's properties. When form is submitted, student's properties should change. The problem is when I want to set initial value of input elements as a properties of a current selected student. The value of input elements is filled with properties of a current student, but when I try to type something in that input, it's value does not change.
Code of Parent component
class App extends Component {
constructor(props){
super(props);
this.state = {
students :listStudents(),
visible: false,
index: 0,
student: listStudents()[0]
};
this.onClick = this.onClick.bind(this);
this.onSubmit = this.onSubmit.bind(this);
this.onNewStudentSubmit = this.onNewStudentSubmit.bind(this);
}
onClick(index){
if(this.state.visible){
this.setState({
visible: false,
index: 0
});
}
else {
let student1 = this.state.students
.filter(s => s.index === index);
this.setState({
visible: true,
index: index,
student: student1[0]
});
}
}
onSubmit(student){
let list = this.state.students
.map(s => {
if(s.index === this.state.index)
return student;
return s;
});
this.setState({
students : list,
visible: false
});
}
render() {
return (
<div className="App">
<StudentsList students={this.state.students} onClick={this.onClick}/>
<EditStudentDetails student={this.state.student} visible={this.state.visible} onSubmit={this.onSubmit}/>
<CreateStudent onSubmit={this.onNewStudentSubmit}/>
</div>
);
}
}
export default App;
onClick function changes selected student and stores it in state.student.
onSubmit function is triggered when the student's editing form is submitted.
Render returns the list of all students and a editing component which can be visible or not. Below is code of my editing component.
import React from 'react';
class EditStudentDetails extends React.Component{
constructor(props){
super(props);
this.state = {
name: "",
surname: "",
index : "",
class : "",
visible: ""
};
this.handleSubmit = this.handleSubmit.bind(this);
this.handleNameChange = this.handleNameChange.bind(this);
this.handleSurnameChange = this.handleSurnameChange.bind(this);
this.handleClassChange = this.handleClassChange.bind(this);
this.handleIndexChange = this.handleIndexChange.bind(this);
}
handleSubmit(e){
const student = {
name: this.state.name,
surname: this.state.surname,
index : this.state.index,
class : this.state.class
};
this.props.onSubmit(student);
e.preventDefault();
}
handleNameChange(e){
const newName = e.target.value;
this.setState({
name: newName
});
}
handleSurnameChange(e){
const newName = e.target.value;
this.setState({
surname: newName
});
}
handleIndexChange(e){
const newIndex = e.target.value;
this.setState({
index: newIndex
});
}
handleClassChange(e){
const newClass = e.target.value;
this.setState({
class: newClass
});
}
render(){
const type = this.props.visible ? {display: 'block'} : {display: 'none'} ;
return(
<div style={type}>
<form className="form-group" onSubmit={this.handleSubmit}>
Име
<input className="Name" type="text" onChange={this.handleNameChange} value={this.props.student.name}/>
Презиме
<input className="Surname" type="text" onChange={this.handleSurnameChange} value={this.props.student.surname}/>
Индекс
<input className="Index" type="text" onChange={this.handleIndexChange} value={this.props.student.index}/>
Насока
<input className="Class" type="text" onChange={this.handleClassChange} value={this.props.student.class}/>
<input className="submit btn" type="submit" value="Промени"/>
</form>
</div>
);
}
}
export default EditStudentDetails;
I try to set initial value by setting each input's value to the appropriate prop. Then when something is changed in the input component state should update. But as I said, the value of each input does not change.
You are telling React to use the passed prop as the input value, and since the props are not changed, the value isn't either. Set the passed props to the component state and update the state when the input is changed.
If you want to shave of some bytes, you could also use a more general onChange method as in the example below, given you are able to set a name property on the input fields.
class EditStudentDetails extends React.Component {
constructor(props) {
super(props);
this.state = {
name: "",
surname: "",
index: "",
class: "",
visible: "",
...this.props.student
};
this.handleSubmit = this.handleSubmit.bind(this);
this.handleChange = this.handleChange.bind(this);
}
handleSubmit(e) {
const student = {
name: this.state.name,
surname: this.state.surname,
index: this.state.index,
class: this.state.class
};
this.props.onSubmit(student);
e.preventDefault();
}
handleChange(e) {
this.setState({
[e.target.name]: e.target.value
});
}
render() {
const type = this.props.visible ? { display: 'block' } : { display: 'none' };
return (
<div style={type}>
<form className="form-group" onSubmit={this.handleSubmit}>
Име
<input className="Name" name="name" type="text" onChange={this.handleChange} value={this.state.name} />
Презиме
<input className="Surname" name="surname" type="text" onChange={this.handleChange} value={this.state.surname} />
Индекс
<input className="Index" name="index" type="text" onChange={this.handleChange} value={this.state.index} />
Насока
<input className="Class" name="class" type="text" onChange={this.handleChange} value={this.state.class} />
<input className="submit btn" type="submit" value="Промени" />
</form>
</div>
);
}
}
The problem is here.
<input className="Name" type="text" onChange={this.handleNameChange} value={this.props.student.name}/>
The value of the input is this.props.student.name,but in the this.handleNameChange, you change this.state.name,so when you type something,you can't see the change in the input value.
I suppose you need something like this:
this.state = {
class: props.student.name
}
...
<input className="Name" type="text" onChange={this.handleNameChange} value={this.state.name}/>
I am new to React trying to write a very simple project that fetches input of both text boxes and when button is clicked, the 'data' in text boxes is printed on paragraph.
How do I fetch text's in input text boxes when button is clicked?
class Input extends Component {
state = {
tagged: false,
message: '',
}
handleClick(e) {
this.setState({tagged: true});
e.preventDefault();
console.log('The link was clicked.');
}
render() {
return (
<div id="id" style={divStyle}>
<p> hello </p>
<input
style = {textStyle}
placeholder="user#email.com"
type="text">
</input>
<input
style = {textStyle}
placeholder="tag"
type="text">
</input>
<button
onClick={(e) => this.handleClick(e)}
style={buttonStyle}>
{this.state.tagged ? 'Tagged' : 'Tag ' }
</button>
<p>
{this.state.tagged ? 'Clicked' : 'Still' }
</p>
</div>
)
}
}
You can add onChange event handler in each input.
class Input extends Component {
state = {
tagged: false,
message: '',
input1: '',
input2: '',
}
handleClick(e) {
// access input values in the state
console.log(this.state) // {tagged: true, input1: 'text', input2: 'text2'}
this.setState({tagged: true});
e.preventDefault();
console.log('The link was clicked.');
}
handleInputChange = (e, name) => {
this.setState({
[name]: e.target.value
})
}
render() {
return (
<div id="id" style={divStyle}>
<p> hello </p>
<input
style = {textStyle}
placeholder="user#email.com"
type="text"
onChange={(e) => this.handleInputChange(e, 'input1')}
>
</input>
<input
style = {textStyle}
placeholder="tag"
type="text"
onChange={(e) => this.handleInputChange(e, 'input2')}
>
</input>
<button
onClick={(e) => this.handleClick(e)}
style={buttonStyle}>
{this.state.tagged ? 'Tagged' : 'Tag ' }
</button>
<p>
{this.state.tagged ? 'Clicked' : 'Still' }
</p>
</div>
)
}
}
There are two different ways of working with react inputs - you can either make them controlled or uncontrolled. When you say fetch text from inputs, this is called uncontrolled components and means that form data is handled by the DOM itself and not by react.
This is achieved by using ref and literally getting a reference to your input and fetching its value when you need it. you can read more about this approach in react docs.
According to react docs, it is recommended using controlled components
In most cases, we recommend using controlled
components to implement forms. In a controlled
component, form data is handled by a React component.
This means that you don’t use references to the inputs and instead handle changes of your inputs with an event handler and update state with the new values that the user has entered into the input fields. According to react docs here is how react handles form with controlled components:
the React component that
renders a form also controls what happens in that form on subsequent
user input. An input form element whose value is controlled by React in this way is called a “controlled component”.
In your case you can do this if you choose controlled inputs:
class ControlledInput extends React.Component {
constructor(props) {
super(props);
this.state = {
tagged: false,
firstInput: '',
secondInput: ''
}
this.handleChange = this.handleChange.bind(this);
}
handleChange(event) {
this.setState({ [event.target.name]: event.target.value });
}
handleClick(e) {
this.setState({ tagged: true });
e.preventDefault();
console.log('The link was clicked.');
}
render() {
const { firstInput, secondInput, tagged } = this.state;
return (
<div id="id">
{tagged && <p>{firstInput} {secondInput}</p> }
<input
value={firstInput}
name="firstInput"
onChange={this.handleChange}
type="text" />
<input
value={secondInput}
name="secondInput"
onChange={this.handleChange}
type="text" />
<button onClick={(e) => this.handleClick(e)}>
{tagged ? 'Tagged' : 'Tag '}
</button>
</div>
)
}
}
Here you put the inputs' values on state and update state when the user writes something in your inputs. If you however want to use uncontrolled components you can do it this way:
class UncontrolledInput extends React.Component {
state = {
tagged: false,
message: '',
}
handleClick(e) {
e.preventDefault();
const messageFromInputs = `${this.firstInput.value} ${this.secondInput.value}`;
this.setState({ tagged: true, message: messageFromInputs });
}
render() {
return (
<div id="id">
<p>{this.state.message}</p>
<input ref={(input) => this.firstInput = input} type="text" />
<input ref={(input) => this.secondInput = input} type="text" />
<button onClick={(e) => this.handleClick(e)}>
{this.state.tagged ? 'Tagged' : 'Tag '}
</button>
<p>
{this.state.tagged ? 'Clicked' : 'Still'}
</p>
</div>
)
}
}
Here you will actually fetch values from your inputs when the button is clicked.
I made a working example with both ways on codesandbox.
I have a controlled form. If you type in the textarea and click the submit button it works. However im trying to also make the form submit when you press enter while typing. The following instead of submitting the form reload the page.
import React from 'react';
class PostComment extends React.Component {
constructor(props) {
super(props);
this.state = { value: '' };
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.keyDown = this.keyDown.bind(this);
}
handleChange(e) {
e.preventDefault();
this.setState({ value: e.target.value });
}
keyDown(e) {
if (e.keyCode == 13 && e.shiftKey == false) {
e.preventDefault();
this.myFormRef.submit();
}
}
handleSubmit(e) {
e.preventDefault();
const text = e.target.body.value;
// Call backend here
e.target.body.value = '';
}
render() {
return (
<form onSubmit={this.handleSubmit} ref={el => (this.myFormRef = el)}>
<textarea
rows="3"
name="body"
onKeyDown={this.keyDown}
value={this.state.value}
onChange={this.handleChange}
/>
<button className="btn" type="submit">
Comment
</button>
</form>
);
}
}
export default PostComment;
My first guess would be that *.submit() does not trigger the onSubmit event, see also a similar question here, which suggests calling the onsubmit handler directly (in this case this would mean e.g. calling this.handleSubmit with a "fake" event payload) ... Another way you could work around this problem would be to trigger the submit button click rather than the form submit on enter:
keyDown () {
if (e.keyCode == 13 && e.shiftKey == false) {
e.preventDefault();
this.button.click();
}
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<textarea
rows="3"
name="body"
onKeyDown={this.keyDown}
value={this.state.value}
onChange={this.handleChange}
/>
<button className="btn" type="submit" ref={el => (this.button = el)}>
Comment
</button>
</form>
);
}