React Input Element : Value vs Default Value - javascript

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

Related

I am not able to submit because read property 'value' of undefined

I have an input and a button and it seems that it cannot detect the value of the input. I didn't use any form tag and I am wondering if that is the cause. What am I missing here? Many thanks in advance and greatly appreciated.
<div className="input-group mb-3">
<input type="text" className="form-control" placeholder="add a post"/>
<div class="input-group-append">
<button type="submit" class="btn btn-primary" onClick={(e) => {
makePost(e.target[0].value, item._id)}} type="button">Post</button>
</div>
</div>
e.target gives you the reference for the button, and no data of the form can be found there.
You have duplicate type property type="submit" and type="button", type=submit will submit the form, and type=button is just a button.
If you don't want to use React's state, which you probably should anyway. https://reactjs.org/docs/hooks-state.html, you can wrap your input elements in a form element and attach an onSubmit handler for the form. Change the button's type to submit (remember to add preventDefault(), so it won't "POST" the form automatically).
Then in your e.currentTarget you will have access to all the elements inside the form.
const Test = () => {
const onFormSubmit = (e) => {
e.preventDefault();
e.stopPropagation();
const formData = new FormData(e.currentTarget);
for (let [name, value] of formData.entries()) {
/* makePost function here or something */
console.log(name + ":" + value);
}
}
return (
<form onSubmit={onFormSubmit}>
<div className="input-group mb-3">
<input type="text" className="form-control" name={"id_maybe"} placeholder="add a post"/>
<div class="input-group-append">
<button type="submit" class="btn btn-primary">Post</button>
</div>
</div>
</form>
);
}
ReactDOM.render(<Test />, document.getElementById("root"));
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
I think this is what you're looking for
import React, { useState } from "react";
import "./style.css";
export default function App() {
const [value, setValue] = useState("");
const [posts, setPosts] = useState([]);
const onSubmit = () => {
posts.push(value);
setPosts([...posts]);
setValue("");
};
const handleInput = e => {
setValue(e.target.value);
};
return (
<div className="input-group mb-3">
<input
type="text"
className="form-control"
placeholder="add a post"
value={value}
onChange={handleInput}
/>
<div class="input-group-append">
<button class="btn btn-primary" onClick={onSubmit}>
Add Post
</button>
</div>
{posts.map(post => (
<div>{post}</div>
))}
</div>
);
}
e.target[0].value doesn't work. You cannot find the 0th element of e.target. Instead of doing that, you could try directly accesing value using e.target.value instead.
I don't think you're doing it the right way. With all due respect, your code is pretty sloppy. First of all, you have no <form> element. Second, you're doing this in a pretty weird way. Instead of using a separate function, you directly insert an arrow function into button.
You should also use State and add this in your constructor:
this.state = {
items: [],
text: ""
}
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
First of all, add an handleChange button here:
handleChange(event) {
this.setState({ text: event.target.value });
}
You can use something like this for your submit function:
handleSubmit(event) {
event.preventDefault();
const newItem = {
text: this.state.text,
id: performance.now()
};
this.setState(state => ({
items: state.items.concat(newItem),,
text: ""
}));
}
Change this in your render function:
<form>
<input type="text" className="form-control" onChange= {this.handleChange} value={this.state.text} placeholder="add a post"/>
<div class="input-group-append">
<button type="submit" class="btn btn-primary" onClick={this.handleSubmit}>Post</button>
</div>
</form>
You seem to be a newcomer to React, so why don't you read the React Tutorial?

validate Google recaptcha in react login application

I have a react application in which I use a google Recaptcha in the Login component. I don't want users to log in without checking the "I'm not a robot" Recaptcha. I am using a state but I am not as successful as the state never changes, how can I do? I have the code below.
export default class Login extends Component {
constructor(props) {
super(props);
this.state = {
captcha: false,
}
}
callBack = () => {
console.log("something inside re captcha");
}
verifyBack = (response) => {
if (response) {
this.setState({
captcha: true,
});
}
}
onSubmit = () => {
// checking if captcha state is true to log in but not successful.
// log in only after checking the I'm not a robot box (assuming username/password matches).
}
render() {
return (
<div>
<div class="container">
<label for="uname"><b>Username</b></label>
<input type="text" placeholder="Enter Username" name="uname" required />
<label for="psw"><b>Password</b></label>
<input type="password" placeholder="Enter Password" name="psw" required />
<button type="submit" onClick={this.onSubmit}>Login </button>
<label>
<input type="checkbox" checked="checked" name="remember" /> Remember me
</label>
</div>
<div class="container" style="background-color:#f1f1f1">
<button type="button" class="cancelbtn">Cancel</button>
<span class="psw">Forgot password?</span>
</div>
<div className="row invisible-recaptch">
<ReCAPTCHA
sitekey="6Lf8zsgUAAAAAHV1_VcrNDHfWuYAXw1tUSLnexQg"
render="explicit"
onloadCallback={this.callBack}
verifyCallback={this.verifyBack}
/>
</div>
</div>
);
}}
Based on your code,
I think you need to bind your verifyBack function in constructor.
constructor(props) {
super(props);
...
this.verifyBack = this.verifyBack.bind(this);
}
Your problem will solve.Inside verifyBack function u do not have
access of this so that setState is not working.bind the function with
this will help u to do this.

React Submit Form Not Sending POST Request

I am trying to create a frontend for a Spring Boot application and I chose React but I do not have much experience with React or JavaScript.
So I have a form that I am trying to use to send a post request but when I press the submit button, nothing seems to happen. I assume its my onSubmit handler that's the problem but I don't know what is wrong with it. When I send the POST request manually it works fine so I don't think it's the REST API thats causing an issue.
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import axios from 'axios';
import { Link } from 'react-router-dom';
class Create extends Component {
constructor() {
super();
this.state = {
name: '',
email: '',
title: '',
description: ''
};
}
onChange = (e) => {
const state = this.state
state[e.target.name] = e.target.value;
this.setState(state);
}
onSubmit = (e) => {
e.preventDefault();
const { name, email, title, description } = this.state;
axios.post('/create', { name, email, title, description })
.then((result) => {
this.props.history.push("/")
});
}
render() {
const { name, email, title, description } = this.state;
return (
<div class="container">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">
Send Message
</h3>
</div>
<div class="panel-body">
<h4><Link to="/"><span class="glyphicon glyphicon-th-list" aria-hidden="true"></span> Message List</Link></h4>
<form onSubmit={this.onSubmit}>
<div class="form-group">
<label for="name">Name:</label>
<input type="text" class="form-control" name="name" onChange={this.onChange}/>
</div>
<div class="form-group">
<label for="email">Email:</label>
<input type="text" class="form-control" name="email" onChange={this.onChange}/>
</div>
<div class="form-group">
<label for="title">Title:</label>
<input type="text" class="form-control" name="title" onChange={this.onChange}/>
</div>
<div class="form-group">
<label for="description">Description:</label>
<input type="text" class="form-control" name="description" onChange={this.onChange}/>
</div>
<button type="submit" class="btn btn-default">Submit</button>
</form>
</div>
</div>
</div>
);
}
}
export default Create;
The first rule of React is, You do not update state property directly (or React wouldn't know that the state has changed).
It's not easy to tell how React would behave if you do so.
So instead of setting the state value directly,
onChange = (e) => {
const state = this.state
state[e.target.name] = e.target.value;
this.setState(state);
}
Change it like this and try to submit again.
onChange = (e) => {
const state = this.state
this.setState({[e.target.name]: e.target.value});
}

Duplicate the input in the form React

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.

React Submit Event - Enter Key Not Working

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>

Categories

Resources