Why doesn't my React Js form accept user input? - forms

I have a simple AddUser component and in the render function I am returning the following html:
<form ref="form" className="users-form" onSubmit={ this.handleAddNew }>
<input ref="username" type="text" name="username" placeholder="username"
value={this.state.username} onChange={function() {}} /><br />
<input ref="email" type="email" name="email" placeholder="email"
value={this.state.email} onChange={function() {}} /><br />
<button type="submit"> Add User </button>
</form>
I am binding the state of username and email to this.state which I am setting to blank in getInitialState like so:
getInitialState() {
return { username: '', email: '' };
}
I am binding state to the form so I can set it to blank after form submission.
The problem with this setup is that the form now renders as readonly.
I cannot get any user input into either text fields. What am I doing wrong?

Your input fields are controlled components, since you are using the value property. This makes the inputs readonly and they will always reflect the value, the variable (in this case, the state variable) holds. You have to explicitly setState onChange since you are setting username field as a state variable.
Read more about it here
onUserNameChange : function(e){
this.setState({username : e.target.value})
},
render: function(){
return ...
<input ref="username" type="text" name="username" placeholder="username"
value={this.state.username} onChange={this.onUserNameChange} /><br />
...
<button type="submit"> Add User </button>
</form>
}
A better way to do this is :
onChange : function(field,e){
this.setState({field: e.target.value});
},
render : function(){
return <form ref="form" className="users-form" onSubmit={ this.handleAddNew }>
<input ref="username" type="text" name="username" placeholder="username"
value={this.state.username} onChange={this.onChange.bind(this,"username")} /><br />
<input ref="email" type="email" name="email" placeholder="email"
value={this.state.email} onChange={this.onChange.bind(this,"email")} /><br />
<button type="submit"> Add User </button>
</form>
}

It looks like you saw the console warning about controlled fields needing an onChange handler and added one just to shut the warning up :)
If you replace your empty onChange handler functions with onChange={this.handleChange} and add this method to your component, it should work:
handleChange(e) {
this.setState({[e.target.name]: e.target.value})
}
(Or for people not using an ES6 transpiler:)
handleChange: function(e) {
var stateChange = {}
stateChange[e.target.name] = e.target.value
this.setState(stateChange)
}
However, if your component is an ES6 class extending React.Component (instead of using React.createClass()), you will also need to ensure the method is bound to the component instance properly, either in render()...
onChange={this.handleChange.bind(this)}
...or in the constructor:
constructor(props) {
super(props)
// ...
this.handleChange = this.handleChange.bind(this)
}

Related

How to disable autocomplete with v-form

I want to disable chrome autocomplete in my v-form. How do I do that? I don't see a autocomplete property on the v-form.
https://next.vuetifyjs.com/en/api/v-form/
While it is a property on a normal html form
https://www.w3schools.com/tags/att_form_autocomplete.asp
By setting autocomplete="username" and autocomplete="new-password" on v-text-field you can actually turn off the autocomplete in chrome.
here is a code that worked for me:
<v-form lazy-validation ref="login" v-model="validForm" #submit.prevent="submit()">
<v-text-field
v-model="user.email"
label="Email"
autocomplete="username"
/>
<v-text-field
v-model="user.password"
label="Password"
type="password"
autocomplete="new-password"
/>
<v-btn type="submit" />
</v-form>
Edit: autocomplete isn't set as a prop in vuetify docs but if you pass something to a component which isn't defined as prop in that component, it will accept it as an attribute and you can access it through $attrs.
here is the result of the above code in vue dev tools:
and here is the rendered html:
I wasn't able to get autofill disabled with the above methods, but changing the name to a random string/number worked.
name:"Math.random()"
https://github.com/vuetifyjs/vuetify/issues/2792
use autocomplete="off" in <v-text-field
<v-text-field
autocomplete="off"
/>
Just add:
autocomplete="false"
to your <v-text-field> or any input
autocomplete="null"
This one prevents Chrome autofill feature
I have not been able to get any of the previous proposals to work for me, what I finally did is change the text-flied for a text-area of a single line and thus it no longer autocompletes
Try passing the type='search' and autocomplete="off" props.
I also ran into a similar problem. Nothing worked until I found this wonderful Blog "How to prevent Chrome from auto-filling on Vue?" by İbrahim Turan
The main catch is that we will change the type of v-text-field on runtime. From the below code you can see that the type of password field is assigned from the value fieldTypes.password. Based on focus and blur events we assign the type of the field. Also, the name attribute is important as we decide based on that in the handleType() function.
I'm also pasting the solution here:
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<template>
<div id="app">
<div v-if="isloggedin" class="welcome">
Welcome {{username}}
</div>
<div v-else id="form-wrapper">
<label for="username">Username: </label>
<input
v-model="username"
class="form-input"
type="text"
name="username"
value=""
autocomplete="off"
/>
<label for="password">Password: </label>
<input
v-model="password"
class="form-input"
:type="fieldTypes.password"
name="password"
value=""
#focus="handleType"
#blur="handleType"
autocomplete="off"
/>
<button class="block" type="button" #click="saveCredentials">
Submit Form
</button>
</div>
</div>
</template>
<script>
export default {
name: 'App',
data() {
return {
username: '',
password: '',
isloggedin: false,
fieldTypes: {
password: 'text',
}
}
},
methods: {
saveCredentials() {
this.isloggedin = true;
},
handleType(event) {
const { srcElement, type } = event;
const { name, value } = srcElement;
if(type === 'blur' && !value) {
this.fieldTypes[name] = 'text'
} else {
this.fieldTypes[name] = 'password'
}
}
}
}
</script>

Not recognising Event Object on Submit of Form with Radio Buttons

I am writing a react component that holds a form, with radio buttons inside it. I've tried to create onChange() and handleSubmit() functions that would collect the value of the selected button and console log the value of it, but the event object isn't being recognised, and I get this error:
Uncaught TypeError: Cannot read property 'target' of undefined
Why is this happening and what can I do about it now?
Here is my code:
class NoteInput extends React.Component {
constructor(props) {
super(props);
this.state={
selectedValue: ''
}
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(e) {
this.setState({selectedValue: e.target.value})
}
handleSubmit(e) {
e.preventDefault();
console.log(this.state.selectedValue);
}
render() {
return (
<div>
<form onChange={this.handleChange()} >
<input type="radio" id="0" name="location" value={this.props.locations[0]} />
<label htmlFor="choice1">Safa Park</label>
<input type="radio" id="1" name="location" value={this.props.locations[1]} />
<label htmlFor="choice2">Mercato</label>
<input type="radio" id="2" name="location" value={this.props.locations[2]} />
<label htmlFor="choice3">Burj Khalifa</label>
</form>
<input onSubmit={this.handleSubmit()} type="submit" value="Submit" />
</div>
);
}
}
You are calling functions instead of passing them to event handler. So pass the function instead, by removing () like this
onChange={this.handleChange}
onSubmit={this.handleSubmit}

Input field is not working

When I am using state variable as a value for the input fields, second input field is not working.
Here is the code:
<input
type="text"
className="form-control"
placeholder="mobileNumber"
onChange={this.handleLoginMobileNumber}
onKeyUp={this.handleLoginMobileNumber}
value={this.state.loginMobileNumber}
/>
<input
type="text"
className="form-control"
placeholder="Passcode"
maxLength="4"
value={this.state.loginPasscode}
/>
<br/>
<button
className="btn btn-large btn-primary medata-login-form-input medata-login-form-submit-button"
onClick={this.submitLogin}>
Log in
</button>
Help me, Thanks.
Issue is, you are using Controlled Component and you forgot to define the onChange method and update the state value with password field, because of that password field is read only.
Check this example:
class App extends React.Component{
constructor(){
super();
this.state = {
loginMobileNumber: '',
loginPasscode: ''
}
}
handleLoginMobileNumber(e){
this.setState({loginMobileNumber: e.target.value})
}
loginPasscode(e){
this.setState({loginPasscode: e.target.password})
}
render(){
return(
<div>
<input
type="text"
className="form-control"
placeholder="mobileNumber"
onChange={this.handleLoginMobileNumber.bind(this)}
value={this.state.loginMobileNumber}
/>
<input
type="password"
className="form-control"
placeholder="Passcode"
maxLength="4"
value={this.state.loginPasscode}
onChange={this.loginPasscode.bind(this)}
/>
</div>
)
}
}
ReactDOM.render(<App/>, 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'/>

In Redux, how to get user input

I have a form, how to get the use input in the handleSubmit() method?
handleSubmit(e) {
e.preventDefault()
//how to get the user input?
}
render() {
return (
<div className="col-sm-4">
<form onSubmit={this.handleSubmit}>
<input type="text" placeholder="user"/>
<input type="text" placeholder="comments"/>
<input type="submit" hidden/>
</form>
</div>
)
}
so far, I know three solutions:
The first one, use refs, but I can see there are lots of people saying that we should avoid using it
The second one, add onChange() to each <input>, e.g.
class Example extends React.Component {
state = {
inputValue: ""
};
handleInputChanged(e) {
this.setState({
inputValue: e.target.value
});
}
render() {
return (
<div>
<input onChange={this.handleInputChanged.bind(this)} value={this.state.inputValue}>
</div>
);
}
}
this one is fine with a few inputs. But if the form has 20 input fields, then there are 20 different onChange methods?
third, use some npm module, like redux-form.
any other suggestion? Thanks
You can actually just do an onChange on the parent form like so:
onChange(e) {
switch(e.target.type) {
case 'checkbox':
this.setState({ [e.target.name]: e.target.checked });
break;
default:
this.setState({ [e.target.name]: e.target.value });
break;
}
}
// in render
<form onChange={this.onChange.bind(this)}>
<input name="foo1" />
<input name="foo2" />
<input name="foo3" />
<input name="foo4" />
<input name="foo5" />
<input name="foo6" />
<input name="foo7" />
<input name="foo8" />
</form>
There are certain libraries like https://github.com/christianalfoni/formsy-react, https://github.com/prometheusresearch/react-forms. These forms have additional functions pre written for form submitting, validations. I think using refs is a tedious and unwanted task if the form is big with the reason being that if it is controlled form you need to access the state value for controlled components which brings unnecessary complications. You can do it but it is better to use prewritten libraries.

Disable submit button when form invalid with AngularJS

I have my form like this:
<form name="myForm">
<input name="myText" type="text" ng-model="mytext" required />
<button disabled="{{ myForm.$invalid }}">Save</button>
</form>
As you may see, the button is disabled if the input is empty but it doesn't change back to enabled when it contains text. How can I make it work?
You need to use the name of your form, as well as ng-disabled: Here's a demo on Plunker
<form name="myForm">
<input name="myText" type="text" ng-model="mytext" required />
<button ng-disabled="myForm.$invalid">Save</button>
</form>
To add to this answer. I just found out that it will also break down if you use a hyphen in your form name (Angular 1.3):
So this will not work:
<form name="my-form">
<input name="myText" type="text" ng-model="mytext" required />
<button ng-disabled="my-form.$invalid">Save</button>
</form>
Selected response is correct, but someone like me, may have issues with async validation with sending request to the server-side - button will be not disabled during given request processing, so button will blink, which looks pretty strange for the users.
To void this, you just need to handle $pending state of the form:
<form name="myForm">
<input name="myText" type="text" ng-model="mytext" required />
<button ng-disabled="myForm.$invalid || myForm.$pending">Save</button>
</form>
If you are using Reactive Forms you can use this:
<button [disabled]="!contactForm.valid" type="submit" class="btn btn-lg btn primary" (click)="printSomething()">Submit</button>
We can create a simple directive and disable the button until all the mandatory fields are filled.
angular.module('sampleapp').directive('disableBtn',
function() {
return {
restrict : 'A',
link : function(scope, element, attrs) {
var $el = $(element);
var submitBtn = $el.find('button[type="submit"]');
var _name = attrs.name;
scope.$watch(_name + '.$valid', function(val) {
if (val) {
submitBtn.removeAttr('disabled');
} else {
submitBtn.attr('disabled', 'disabled');
}
});
}
};
}
);
For More Info click here
<form name="myForm">
<input name="myText" type="text" ng-model="mytext" required/>
<button ng-disabled="myForm.$pristine|| myForm.$invalid">Save</button>
</form>
If you want to be a bit more strict