Can't clear form/state after input in React.js - forms

I have a form which ultimately will be used as the UI to make some API calls to Open weather map.
Right now when I submit the a zip code in the input field, upon submission [object Object] propagates the field like in the screen shot below.
The call to the API is working as I am getting the JSON for the correct zip code...
But shouldn't this in the handleSubmit take care of everything i.e. using Object.assign to create new state and then using form.zipcode.value = ''; to clear out the input?
Thanks in advance!!
handleSubmit(event) {
event.preventDefault();
var form = document.forms.weatherApp;
api.getWeatherByZip(this.state.zipcode).then(
function(zip) {
console.log('zip', zip);
this.setState(function() {
return {
zipcode: Object.assign({}, zip),
};
});
}.bind(this)
);
form.zipcode.value = '';
}
I have enclosed all of the component's code here.
import React, { Component } from 'react';
import * as api from '../utils/api';
import '../scss/app.scss';
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
zipcode: [],
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({
zipcode: event.target.value,
});
}
handleSubmit(event) {
event.preventDefault();
var form = document.forms.weatherApp;
api.getWeatherByZip(this.state.zipcode).then(
function(zip) {
console.log('zip', zip);
this.setState(function() {
return {
zipcode: Object.assign({}, zip),
};
});
}.bind(this)
);
form.zipcode.value = '';
}
render() {
return (
<div className="container">
<form name="weatherApp" onSubmit={this.handleSubmit}>
<h2>Open Weather App</h2>
<div className="row">
<div className="one-half column">
<label htmlFor="insertMode">Insert your location</label>
<input
name="zipcode"
className="u-full-width"
placeholder="please enter your zipcode"
type="text"
autoComplete="off"
value={this.state.zipcode}
onChange={this.handleChange}
/>
</div>
<div className="one-half column">
<label htmlFor="showMin">show minimum</label>
<input type="checkbox" />
<label htmlFor="showMax">show maximum</label>
<input type="checkbox" />
<label htmlFor="showMean">show mean</label>
<input type="checkbox" />
</div>
</div>
<div className="row">
<div className="two-half column">
<input type="submit" value="Submit" />
</div>
</div>
</form>
</div>
);
}
}

You should let react manage the changes to the DOM rather that editing it manually. As the value of your input field is already bound to this.state.zipcode to reset it just invoke this.setState({zipcode: ''}) instead of form.zipcode.value='';.

Related

How to enable required validation in vuelidate based on onChange event of select field

I have to enable required validation for the input field based on the onChange event of select field. I'm using vuelidate package for form validation in my project. Kindly provide solution to accomplish it.
My Template Code Below:
<template>
<section class="page_blk">
<form #submit="submitForm($event)" class="cryp_form">
<div class="input_ctrl_wrp">
<label for="username">Template</label>
<div class="input_select">
<select #change="getTemplate" v-model="$v.adForm.tnc.$model" name="" id="">
<option value="">Select</option>
<option value="New">New</option>
<option :value="term.idTnCTemplate"
v-for="term in termsList"
:key="term.idTnCTemplate">{{term.title}}</option>
</select>
<i class="fal fa-angle-down"></i>
</div>
</div>
<div class="input_ctrl_wrp">
<label for="username">Title</label>
<div class="input_text">
<input v-model="$v.adForm.title.$model" placeholder="" type="text">
</div>
</div>
<div class="input_ctrl_wrp">
<label for="username">Terms Of Trade</label>
<div class="input_textarea">
<textarea v-model="$v.adForm.content.$model" name="" rows="10"></textarea>
</div>
</div>
</form>
</section>
</template>
My Script Below:
<script>
import { required,requiredIf, decimal, numeric } from "vuelidate/lib/validators";
export default {
data() {
return {
adForm: {
tnc: '',
title: '',
content: '',
}
}
},
validations: {
adForm: {
tnc: {
required
},
title: {
required
},
content: {
required: requiredIf( (abc) => {
console.log('abc',abc)
return true;
})
},
schedule: {
required
}
}
},
methods: {
submitForm(e) {
},
getTemplate(e) {
}
},
mounted() {
}
}
</script>
I want to toggle the validation to required for the title and content field, if the user select new and other option from dropdown. Please provide solution to accomplish it. Thanks in advance.

Reactjs submit form and setState not working first time

I have a submit action for my form which basically validates on submit.
It is working as i expect because when i submit the form it renders the errors. But the issue occurs when i do the submit i do not want to do the ajax request as the form is invalid. I notice that on the first submit the emailError is not set (default) but the second submit the state contains the correct emailError set to true.
I understand from the react docs that setState is not available immeditely as it is pending.
How can i get around this issue?
My code is below
import React, { Component } from 'react';
import isEmail from 'validator/lib/isEmail';
class formExample extends Component
{
constructor(props) {
super(props);
this.state = {
email: '',
emailError: false
};
this.register = this.register.bind(this);
this.updateState = this.updateState.bind(this);
}
updateState(e) {
this.setState({ email: e.target.value });
}
validateEmail() {
if (!isEmail(this.state.email)) {
console.log("setting state");
this.setState({ emailError: true });
return;
}
console.log(this.state);
this.setState({ emailError: false });
}
register(event) {
event.preventDefault();
this.validateEmail();
//only if valid email then submit further
}
render() {
return (
<div className="row">
<div className="col-md-2 col-md-offset-4"></div>
<div className="col-lg-6 col-lg-offset-3">
<form role="form" id="subscribe" onSubmit={this.register}>
<div className="form-group">
<input type="text" className="form-control" placeholder="Email..." name="email" value={this.state.email} onChange={this.updateState} />
<div className="errorMessage">
{this.state.emailError ? 'Email address is invalid' : ''}
</div>
</div>
<div className="input-group input-group-md inputPadding">
<span className="input-group-btn">
<button className="btn btn-success btn-lg" type="submit">
Submit
</button>
</span>
</div>
</form>
</div>
</div>
);
}
}
export default formExample;
in register you call validateEmail, but not return anything, so the rest of the function get's called.
setState is async! so you cannot count on it in the rest of register.
Try this:
validateEmail() {
const isEmailError = !isEmail(this.state.email)
this.setState({ emailError: isEmailError });
return isEmailError;
}
register(event) {
if(this.validateEmail()){
//ajax
};
}
other approach will be:
validateEmail(ajaxCb) {
const isEmailError = !isEmail(this.state.email)
this.setState({ emailError: isEmailError }, ajaxCb);
}
register(event) {
function ajaxCb(){...}
this.validateEmail(ajaxCb)
}

React updating state in two input fields from form submission

I am trying to make a simple contact form using React. Eventually I will send the data collected from the state to a database, but for right now I am trying to just get it to console log the correct values.
Right now, the email field overrides the name field and when I console log both states, name shows up and email is undefined. Here is my React Component
import React, { Component, PropTypes } from 'react';
import ContactData from '../data/ContactData.js';
class FormContact extends Component {
constructor(props) {
super(props)
this.state = {
name: '',
email: '',
textArea: ''
}
}
handleChange(event) {
event.preventDefault();
this.setState({
name: event.target.value,
email: event.target.email
})
}
handleSubmit(event) {
event.preventDefault();
console.log(this.state.name + ' ' + this.state.email);
}
render() {
return (
<form onSubmit={this.handleSubmit.bind(this)}>
<label> Name:
<input type="text" placeholder="Name" value={this.state.name} onChange={this.handleChange.bind(this)} />
</label><br />
<label> Email:
<input type="text" placeholder="Email" value={this.state.email} onChange={this.handleChange.bind(this)}/>
</label><br />
<input className="btn btn-primary" type="submit" value="Submit" />
</form>
)
}
}
FormContact.PropTypes = {
subName: PropTypes.string,
subEmail: PropTypes.string
}
FormContact.defaultProps = {
subName: 'Sam',
subEmail: ''
}
class Contact extends Component {
render() {
return (
<div>
<h1>CONTACT PAGE</h1>
<FormContact />
</div>
)
}
}
export default Contact;
If I understand what you want, you could do it as follows :
Add an empty object in your state for the form values
formValues: {}
Add the name attribute to your fields
<input name="name" .... />
<input name="email" .... />
then depending on that name update your state in handleChange function
let formValues = this.state.formValues;
let name = event.target.name; // Field name
let value = event.target.value; // Field value
formValues[name] = value;
this.setState({formValues})
And if the values go one level deeper, you could use
value={this.state.formValues["name"]} instead of value={this.state.name} - where name is the value of the name attribute of your input field
Thus, everything together should be as follows :
class Test extends React.Component {
constructor(props) {
super(props)
this.state = {
formValues: {}
}
}
handleChange(event) {
event.preventDefault();
let formValues = this.state.formValues;
let name = event.target.name;
let value = event.target.value;
formValues[name] = value;
this.setState({formValues})
}
handleSubmit(event) {
event.preventDefault();
console.log(this.state.formValues);
}
render(){
return (
<form onSubmit={this.handleSubmit.bind(this)}>
<label> Name:
<input type="text" name="name" placeholder="Name" value={this.state.formValues["name"]} onChange={this.handleChange.bind(this)} />
</label><br />
<label> Email:
<input type="text" name="email" placeholder="Email" value={this.state.formValues["email"]} onChange={this.handleChange.bind(this)}/>
</label><br />
<input className="btn btn-primary" type="submit" value="Submit" />
</form>
)
}
}
React.render(<Test />, document.getElementById('container'));
Here is fiddle.
Hope this helps.
The reference to event.target.email does not exist on the event element. The value of a text input from an inline-event handler would be event.target.value for both email and name. The quick solution is to create a separate handler for each input:
handleChangeName(event) {
event.preventDefault();
this.setState({ name: event.target.value }); //<-- both use the same reference
} // to get the contextual value
handleChangeEmail(event) { // from the inputs v
event.preventDefault(); // |
this.setState({ email: event.target.value }); //<--------------------
}

Meteor-react inserting url into mongodb stores 'null'

I am using form component to insert data into the Mongo-Collection. When I check in terminal for stored information I do successfuly store Title and data from Select input, but have value of null for both url and file inputs.
Here is the code for handling insert method on import folder:
Meteor.methods({
'posts.insert' : function(post) {
return Posts.insert({
createdAt: new Date(),
title: post.title,
social: post.social,
link: this.link,
file: this.file
});
}
});
Here is the component code for handling form submit:
import React, { Component } from 'react';
class AddPost extends Component {
constructor(props) {
super(props);
this.state = {error: ''};
}
handleSubmit(event) {
event.preventDefault();
const title = this.refs.title.value;
const social = this.refs.social.value;
const link = this.refs.link.value;
const file = this.refs.file.value;
Meteor.call('posts.insert', {title, social, link, file});
}
render() {
return (
<div className="modal fade" id="myModal" tabIndex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div className="form-outer">
<form id='add_post' onSubmit={this.handleSubmit.bind(this)}>
<div className='form-text form-header'>
<p><strong>Hey</strong>, master<span className='error'>{this.state.error}</span></p>
<p>Lets share something new today?</p>
</div>
<input ref="title" type="text" className="form-input" placeholder="What about the title?" />
<div className='form-text form-header form-header-distance'>
<p>Where should I point the way?</p>
</div>
<select ref="social" className="form-select">
<option>Select</option>
<option>Instagram</option>
<option>Twitter</option>
</select>
<input ref="link" type="url" className="form-input" placeholder="Point the way" />
<div className='form-text form-header form-header-distance'>
<p>And what about the image?</p>
</div>
<label className="file form-file">
<input ref='file' className='form-input' type="file" id="file" />
<span className="file-custom"></span>
</label>
<button type="button" className="form-button" data-dismiss="modal">Close</button>
<button type="sumbit" className="form-button" >Save</button>
</form>
</div>
</div>
);
}
}
export default AddPost;
P.S: It's out of topic of these question, but I will do appreciate a lot if you could point me to some external resource or explain if it's possible to upload/store new images (not static from public folder) from local machine and serve them to front-end view?
Make your meteor method as below:
Meteor.methods({
'posts.insert'(post){
post.createdAt: new Date();
Posts.insert(post);
}
})

how do you enable/disable submit button based on form contents in Material Design Lite?

I have a submit button for a login form which is disabled by default. I want to enable it when the user enters a valid username/password. There are quite a few examples using AngularJS, JQuery, and other infrastructures but i would like to know a clean way to do it with Material Design Lite. My current code is:
class FrontPage extends Component {
constructor(props, context) {
super(props, context);
this.state = { email: '', password: '' };
}
handleEmailChange() {
this.setState({email: e.target.value})
}
handlePasswordChange() {
this.setState({password: e.target.value})
}
render() {
return(
<form className="frontpage" onSubmit={this.handleLogin}>
<div className="content-grid mdl-grid">
<div className="mdl-cell mdl-textfield mdl-js-textfield">
<input className="mdl-textfield__input" id="email" type="email" value={this.state.email} onChange={this.handleEmailChange}/>
<label className="mdl-textfield__label" htmlFor="email">email...</label>
<span className="mdl-textfield__error">Input is not an email address!</span>
</div>
<div className="mdl-cell mdl-textfield mdl-js-textfield">
<input className="mdl-textfield__input" id="password" type="password" pattern="[A-Z,a-z,0-9\?#\$%&\*\-_=+! ~\.,\/\\]*" value={this.state.password} onChange={this.handlePasswordChange}/>
<label className="mdl-textfield__label" htmlFor="password">password...</label>
<span className="mdl-textfield__error">Input can only contain letters, numbers, and some special characters!</span>
</div>
<div classname="mdl-cell">
<button className="mdl-button mdl-button--raised mdl-button--colored mdl-js-ripple-effect" type="submit" name="login" disabled>Login</button>
</div>
</div>
</form>
)
}
}
<button id='loginBtn' className="mdl-button mdl-button--raised mdl-button--colored mdl-js-ripple-effect" type="submit" name="login" disabled>Login</button>
<script>
function Enable() {
var loginBtn = document.getElementById('loginBtn');
loginBtn.removeAttribute("disabled");
componentHandler.upgradeElement(loginBtn);
}
function Disable() {
var loginBtn = document.getElementById('loginBtn');
loginBtn.setAttribute("disabled","");
componentHandler.upgradeElement(loginBtn);
}
</script>