This is my jsx for the form
import React, { Component } from "react";
import { createUser } from "../HTTPRequests";
import PhoneInput from "react-phone-number-input";
class UserRegForm extends Component {
constructor(props) {
super(props);
this.state = {
email: "",
password: "",
secondPassword: "",
username: "",
phone: "",
current: 0
};
this.handleEmail = this.handleEmail.bind(this);
this.handlePassword = this.handlePassword.bind(this);
this.handleSecondPassword = this.handleSecondPassword.bind(this);
this.handleUsername = this.handleUsername.bind(this);
this.renderSecondPassword = this.renderSecondPassword.bind(this);
this.handleKeyDown = this.handleKeyDown.bind(this);
this.handlePhone = this.handlePhone.bind(this);
}
handleEmail(event) {
this.setState({ email: event.target.value });
}
handlePassword(event) {
this.setState({ password: event.target.value });
}
handleSecondPassword(event) {
this.setState({ secondPassword: event.target.value });
}
handleUsername(event) {
this.setState({ username: event.target.value });
}
handlePhone(phone) {
this.setState({ phone: phone.value });
}
renderSecondPassword() {
var classN;
if (
this.state.secondPassword.length === 0 ||
this.state.secondPassword === this.state.password
) {
classN = "form-control";
} else {
classN = "form-control is-invalid";
}
return (
<div className="form-group">
<label htmlFor="InputPassword2">Introduza novamente a Password</label>
<input
onKeyDown={this.handleKeyDown}
onChange={this.handleSecondPassword}
type="password"
className={classN}
id="InputPassword2"
/>
</div>
);
}
handleKeyDown(event) {
if (event.key === "Enter") {
this.handleSubmit();
}
}
handleSubmit() {
createUser(this.state.email, this.state.password, this.state.username).then(
function(r) {
console.log(r);
}
);
}
render() {
return (
<div className="position-relative m-4">
<form>
<div className="form-group">
<label htmlFor="exampleInputUsername">Nome Completo</label>
<input
onKeyDown={this.handleKeyDown}
onChange={this.handleUsername}
type="username"
className="form-control"
id="exampleInputUsername"
/>
</div>
<div className="form-group">
<label htmlFor="exampleInputEmail1">E-mail</label>
<input
onKeyDown={this.handleKeyDown}
onChange={this.handleEmail}
type="email"
className="form-control"
id="exampleInputEmail1"
aria-describedby="emailHelp"
/>
<small id="emailHelp" className="form-text text-muted">
Nunca partilharemos o seu e-mail com ninguém.
</small>
</div>
<PhoneInput
placeholder="Enter phone number"
value={this.state.phone}
onChange={phone => this.handlePhone({ phone })}
/>
<div className="form-group">
<label htmlFor="InputPassword1">Password</label>
<input
onKeyDown={this.handleKeyDown}
onChange={this.handlePassword}
type="password"
className="form-control"
id="InputPassword1"
/>
</div>
{this.renderSecondPassword()}
<button
type="button"
className="btn btn-primary"
onClick={this.handleSubmit}
>
Submit
</button>
</form>
</div>
);
}
}
export default UserRegForm;
And this is the result...
as you can see the flag just expands to the whole screen.
I have programming experience (C and java), but just started learning HTML and React... So i'm still a bit lost. do I have to wrap the phone number component in something so it behaves? According to documentation the flag should be to the left of the input and not below
Any help is very appreciated
As someone who just encountered the same issue as OP after an update, the fix was very simple:
import 'react-phone-number-input/style.css'
According to last version of the docs : https://github.com/catamphetamine/react-phone-number-input
Related
I am facing this when I am trying to set form error object. Basically, I want to show the errors below each input field. In response, I am getting an array of objects how do I set to my error object?
Error - Maximum update depth exceeded. This can happen when a component calls setState inside useEffect, but useEffect either doesn't have a dependency array, or one of the dependencies changes on every render.
import axios from "axios";
import React, { useState, useEffect, useCallback } from "react";
import { Link } from "react-router-dom";
import { useDispatch, useSelector } from "react-redux";
import { register } from "../actions/userActions";
const Register = () => {
const [countriesList, setCountriesList] = useState("");
const [userRegistration, setUserRegistration] = useState({
firstName: "",
lastName: "",
email: "",
password: "",
fullAddress: "",
city: "",
zipCode: "",
country: "",
phone: "",
terms: true,
});
const [userRegistrationError, setUserRegistrationError] = useState({
firstNameError: "",
lastNameError: "",
emailError: "",
passwordError: "",
fullAddressError: "",
cityError: "",
zipCodeError: "",
countryError: "",
phoneError: "",
termsError: "",
});
const dispatch = useDispatch();
const userRegister = useSelector((state) => state.userRegister);
const { loading, errors, success } = userRegister;
useEffect(() => {
const countries = async () => {
try {
const { data } = await axios.get(
`https://restcountries.eu/rest/v2/all`
);
setCountriesList(data);
} catch (err) {
console.error(err);
}
};
countries();
}, []);
useEffect(() => {
const handleErrors = (errors) => {
errors.map((error) => {
if (error.param === "firstname") {
setUserRegistrationError({
...userRegistrationError,
firstNameError: error.msg,
});
}
if (error.param === "email") {
setUserRegistrationError({
...userRegistrationError,
emailError: error.msg,
});
}
return null;
});
};
if (errors) {
handleErrors(errors);
}
}, [errors, setUserRegistrationError]);
const handleChange = (e) => {
const name = e.target.name;
const value = e.target.value;
setUserRegistration({ ...userRegistration, [name]: value });
};
const handleChkChange = (e) => {
const checked = e.target.checked;
console.log(checked);
setUserRegistration({ ...userRegistration, terms: checked });
};
const handleSubmit = (e) => {
e.preventDefault();
try {
dispatch(register());
} catch (error) {
console.error(error);
}
};
return (
<div className="form_container">
<form action="" onSubmit={handleSubmit}>
<div className="row no-gutters">
<div className="col-6 pr-1">
<div className="form-group">
<div className="form-group">
<input
type="text"
name="firstName"
className="form-control"
placeholder="First Name*"
value={userRegistration.firstName}
onChange={handleChange}
/>
<p className="form-vald-error">
{userRegistrationError.firstNameError &&
userRegistrationError.firstNameError}
</p>
</div>
</div>
</div>
<div className="col-6 pr-1">
<div className="form-group">
<input
type="text"
className="form-control"
name="lastName"
placeholder="Last Name*"
value={userRegistration.lastName}
onChange={handleChange}
/>
<p className="form-vald-error">
{userRegistrationError.lastNameError &&
userRegistrationError.lastNameError}
</p>
</div>
</div>
</div>
<hr />
<div className="private box">
<div className="row no-gutters">
<div className="col-6 pr-1">
<div className="form-group">
<input
type="email"
className="form-control"
name="email"
id="email_2"
placeholder="Email*"
value={userRegistration.email}
onChange={handleChange}
/>
<p className="form-vald-error">
{userRegistrationError.emailError &&
userRegistrationError.emailError}
</p>
</div>
</div>
<div className="col-6 pl-1">
<div className="form-group">
<input
type="password"
className="form-control"
name="password"
id="password_in_2"
placeholder="Password*"
value={userRegistration.password}
onChange={handleChange}
/>
<p className="form-vald-error">
{userRegistrationError.passwordError &&
userRegistrationError.passwordError}
</p>
</div>
</div>
<div className="col-12">
<div className="form-group">
<input
type="text"
name="fullAddress"
className="form-control"
placeholder="Full Address*"
value={userRegistration.fullAddress}
onChange={handleChange}
/>
<p className="form-vald-error">
{userRegistrationError.fullAddressError &&
userRegistrationError.fullAddressError}
</p>
</div>
</div>
</div>
{/* /row */}
<div className="row no-gutters">
<div className="col-6 pr-1">
<div className="form-group">
<input
type="text"
className="form-control"
placeholder="City*"
name="city"
value={userRegistration.city}
onChange={handleChange}
/>
<p className="form-vald-error">
{userRegistrationError.cityError &&
userRegistrationError.cityError}
</p>
</div>
</div>
<div className="col-6 pl-1">
<div className="form-group">
<input
type="text"
className="form-control"
placeholder="Postal Code*"
name="zipCode"
value={userRegistration.zipCode}
onChange={handleChange}
/>
<p className="form-vald-error">
{userRegistrationError.zipCodeError &&
userRegistrationError.zipCodeError}
</p>
</div>
</div>
</div>
{/* /row */}
<div className="row no-gutters">
<div className="col-6 pr-1">
<div className="form-group">
<div className="custom-select-form">
<select
className="wide add_bottom_10 form-control"
name="country"
id="country"
value={userRegistration.country}
onChange={handleChange}
>
<option>Country*</option>
{countriesList &&
countriesList.map((country) => (
<option
key={country.alpha2Code}
value={country.alpha2Code}
>
{country.name}
</option>
))}
</select>
<p className="form-vald-error">
{userRegistrationError.countryError &&
userRegistrationError.countryError}
</p>
</div>
</div>
</div>
<div className="col-6 pl-1">
<div className="form-group">
<input
type="text"
className="form-control"
placeholder="Telephone *"
name="phone"
value={userRegistration.phone}
onChange={handleChange}
/>
<p className="form-vald-error">
{userRegistrationError.phoneError &&
userRegistrationError.phoneError}
</p>
</div>
</div>
</div>
{/* /row */}
</div>
<hr />
<div className="form-group">
<label className="container_check">
Accept <Link to="#0">Terms and conditions</Link>
<input
type="checkbox"
name="terms"
checked={userRegistration.terms}
onChange={handleChkChange}
/>
<span className="checkmark" />
<p className="form-vald-error">
{userRegistrationError.termsError &&
userRegistrationError.termsError}
</p>
</label>
</div>
<div className="text-center">
<input
type="submit"
defaultValue="Register"
className="btn_1 full-width"
/>
</div>
</form>
</div>
);
};
export default Register;
your effect depends on userRegistrationError which is an object, reference based. Each time useEffect runs,setUserRegistrationError
creates a new object reference, which leads to an infinite loop since references won't be the same as the previous one.
One approach to avoid this issue and keep the right references, is to pass a callback function to setUserRegistrationError instead than a value. This way userRegistrationError is no longer a dependency, it will be an argument to your function instead:
useEffect(() => {
const handleErrors = (errors) => {
errors.forEach((error) => {
if (error.param === "firstName") {
// here you pass a callback function instead, and userRegistrationError is no longer a dependency
// and returns the next state as expected
setUserRegistrationError(userRegistrationError => ({
...userRegistrationError,
firstNameError: error.msg,
}));
}
if (error.param === "email") {
setUserRegistrationError(userRegistrationError => ({
...userRegistrationError,
emailError: error.msg,
}));
}
});
};
if (errors) {
handleErrors(errors);
}
}, [errors, setUserRegistrationError]);
You have a problem with the second useEffect, the first time you update your state userRegistrationError, the component re-rendered and re-executed the useeffect because the dependency userRegistrationError has changed and the process gets repeated again because the state gets updated every render.
useEffect(() => {
const handleErrors = (errors) => {
errors.map((error) => {
if (error.param === "firstname") {
setUserRegistrationError({
...userRegistrationError,
firstNameError: error.msg,
});
}
if (error.param === "email") {
setUserRegistrationError({
...userRegistrationError,
emailError: error.msg,
});
}
return null;
});
};
if (errors) {
handleErrors(errors);
}
}, [errors, setUserRegistrationError ]); //replace userRegistrationError by setUserRegistrationError
I am following along with this tutorial (https://medium.com/#beaucarnes/learn-the-mern-stack-by-building-an-exercise-tracker-mern-tutorial-59c13c1237a1) and am trying to print to console through the onSubmit function but this is not occurring and I do not know why. I've made sure to use the bind method, and everything seems to be referenced correctly. What am I missing here?
import React, {Component} from 'react';
import DatePicker from 'react-datepicker';
import "react-datepicker/dist/react-datepicker.css";
export default class CreateWorkout extends Component {
constructor(props) {
super(props); // Refers to the parent class constructorq
this.onChangeUsername = this.onChangeUsername.bind(this);
this.onChangeDescription = this.onChangeDescription.bind(this);
this.onChangeReps = this.onChangeReps.bind(this);
this.onChangeDuration = this.onChangeDuration.bind(this);
this.onChangeDate = this.onChangeDate.bind(this);
this.onSubmit = this.onSubmit.bind(this);
this.state = {
username:'',
description: '',
reps: 0,
duration: 0,
date: new Date(),
users: []
}
}
componentDidMount() { // Invoked immediately after a component is mounted
this.setState({
users: ['test user'],
username: 'test user'
});
}
onChangeUsername(e) {
this.setState({
username: e.target.value
});
}
onChangeDescription(e) {
this.setState({
description: e.target.value
});
}
onChangeReps(e) {
this.setState({
reps: e.target.value
});
}
onChangeDuration(e) {
this.setState({
duration: e.target.value
});
}
onChangeDate(date) { // Need to add a date picker library for this
this.setState({
date: date
});
}
// Submit method for submitting an event of the form...
onSubmit(e) {
e.preventDefault();
const workout = {
username: this.state.username,
description: this.state.description,
reps: this.state.reps,
duration: this.state.duration,
date: this.state.date,
};
console.log(workout);
window.location = '/'; // After form is submitted, the location is updated so the user is taken back to the home page
}
render() {
return (
<div>
<h3>Create New Workout Log</h3>
<form onSubmit={this.onSubmit}>
<div className="form-group">
<label>Username: </label>
<select ref="userInput" required className="form-control" value={this.state.username} onChange={this.onChangeUsername}>
{
this.state.users.map(function(user) {
return <option key={user} value={user}>{user}</option>;
})
}
</select>
</div>
<div className="form-group">
<label>Description: </label>
<input type="text" required className="form-control" value={this.state.description} onChange={this.onChangeDescription}/>
</div>
<div className="form-group">
<label>Reps: </label>
<input type="text" className="form-control" value={this.state.reps} onChange={this.onChangeReps}/>
</div>
<div className="form-group">
<label>Duration: </label>
<input type="text" className="form-control" value={this.state.duration} onChange={this.onChangeDuration}/>
</div>
<div className="form-group">
<label>Date: </label>
<div><DatePicker selected={this.state.date} onChange={this.state.onChangeDate}/></div>
</div>
<div className="form-group">
<input type="submit" value="Create Workout Log" className="btn btn-primary"/>
</div>
</form>
</div>
);
}
}
Hi I want to add a progress strength bar for my password but not sure how to link an "eventlistner" in react. So far the code works for checking the password regex but not sure how to add the password strength bar. I don't know how to use addEventListener in react.
Please have a look at my code and tell me what am I doing wrong? Thanks.
import React from 'react'
import {connect} from 'react-redux'
import {registerUserRequest} from '../../actions/register'
import {loginError} from '../../actions/login'
class Register extends React.Component {
constructor(props) {
super(props)
this.state = {
user_name: '',
contact_number: '',
email_address: '',
password: '',
confirm_password: ''
}
this.updateDetails = this.updateDetails.bind(this)
this.submit = this.submit.bind(this)
this.validateEmail = this.validateEmail.bind(this)
this.validatePassword = this.validatePassword.bind(this)
}
componentDidMount() {
this.props.dispatch(loginError(''))
}
updateDetails(e) {
this.setState({[e.target.name]: e.target.value})
}
submit(e) {
e.preventDefault()
e.target.reset()
let {user_name, password, confirm_password, email_address,
contact_number} = this.state
function confirmation (){
if (confirm_password != password)
return false
else
return true
}
const isEmail = this.validateEmail(email_address)
const passwordsNotSame = (confirm_password != password)
const isPass = this.validatePassword(password)
if (!isEmail || passwordsNotSame) return
this.props.dispatch(loginError("Incorrect email/Passwords don't
match"))
else if (!isPass) return this.props.dispatch(loginError('Password
strength must be 8 or above and must include atleast one number '))
else return this.props.dispatch(registerUserRequest(this.state))
}
validateEmail(email) {
var re = /^(([^<>()\[\]\\.,;:\s#"]+(\.[^<>()\[\]\\.,;:\s#"]+)*)|
(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-
Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
var isValid = re.test(String(email).toLowerCase());
// console.log('No joke', isValid)
return isValid
}
validatePassword(pass) {
var re = /^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{8,}$/;
var isPasswordValid = re.test(String(pass));
return isPasswordValid
}
const pass = document.getElementById("password")
pass.addEventListener('keyup', function() {
checkPassword(pass.value)
})
checkPassword(password) {
var strengthBar = document.getElementById("strength")
var strength = 0;
if (password.match(/[a-zA-Z0-9][a-zA-Z0-9]+/)) {
strength += 1
}
if (password.match(/[~<>]+/)) {
strength +=1
}
if (password.match(/[!#£$%^&()]+/)) {
strength +=1
} if (password.length > 5) {
strength +=1
}
switch(strength) {
case 0:
strengthBar.value = 20;
break
case 1:
strengthBar.value = 40;
break
case 2:
strengthBar.value = 60;
break
case 3:
strengthBar.value = 80;
break
case 4:
strengthBar.value = 100;
break
}
}
render() {
const {auth} = this.props
return (
<form onSubmit={this.submit}>
<h1>Register</h1>
<hr />
<b>{auth.errorMessage && <span>{auth.errorMessage}</span>}</b>
<div className="field is-horizontal">
<div className="field-label is-normal">
<label>Username</label >
</div>
<input className="input is-medium"required placeholder="User
Name" type="text" name="user_name" onChange={this.updateDetails}/>
</div>
<div className="field is-horizontal">
<div className="field-label is-normal">
<label>Contact Number</label>
</div>
<input className="input is-medium"required placeholder="Contact
Number" type="text" name="contact_number" onChange=
{this.updateDetails}/>
</div>
<div className="field is-horizontal">
<div className="field-label is-normal">
<label>Email Address</label>
</div>
<div className="field-body">
<div className="field">
<input className="input is-medium"required
placeholder="Email Address" type="text" name="email_address" onChange=
{this.updateDetails}/>
</div>
</div>
</div>
<div className="field is-horizontal">
<div className="field is-horizontal">
<label>Password</label>
<progress max="100" value="0" id="strength"></progress>
</div>
<input className="input is-medium"required
placeholder="Password" type="password" name="password" onChange=
{this.updateDetails}/>
</div>
<div className="field is-horizontal">
<div className="field is-horizontal">
<label>Confirm Password</label>
</div>
<input className="input is-medium"required
placeholder="Confirm Password" type="password" name="confirm_password"
onChange={this.updateDetails}/>
</div>
<input className="button is-primary" value="Register"
type="submit" />
</form>
)
}
}
const mapStateToProps = ({auth}) => ({auth})
export default connect(mapStateToProps)(Register)
This are some changes you can make in your component,
In progress component,
<progress max="100" value={(this.state.password_strength * 20)} id="strength"></progress>
in password input,
<input className="input is-medium"required
placeholder="Password" type="password" name="password" onChange=
{this.updateDetails} onKeyUp={this.checkPassword}/>
In your constructor, initializing password_strength and binding method checkPassword
constructor(props) {
super(props)
this.state = {
user_name: '',
contact_number: '',
email_address: '',
password: '',
confirm_password: '',
password_strength: 0,
}
this.updateDetails = this.updateDetails.bind(this)
this.submit = this.submit.bind(this)
this.validateEmail = this.validateEmail.bind(this)
this.validatePassword = this.validatePassword.bind(this)
this.checkPassword = this.checkPassword.bind(this);
}
and finally, your checkPassword method,
checkPassword(e) {
const password = e.target.value;
const password_strength = 0;
var strength = this.state.password_strength;
if (password.match(/[a-zA-Z0-9][a-zA-Z0-9]+/)) {
strength += 1
}
if (password.match(/[~<>]+/)) {
strength +=1
}
if (password.match(/[!#£$%^&()]+/)) {
strength +=1
} if (password.length > 5) {
strength +=1
}
this.setState({password_strength: strength});
}
If still doesn't work, Please share your working code on codepen.
I am pretty new to react/redux I am pretty confused with this simple form.My error state is always undefined eventhough I am getting the error data from node js server Without error data I can't set my state.
routes/users.js
import express from 'express';
import Validator from 'validator';
import isEmpty from 'lodash/isEmpty'
let router = express.Router();
function ValidateInput(data) {
let errors = {};
if(isEmpty(data.email)){
errors.email = 'This fiels is required'
}
if(!Validator.isEmail(data.email)){
errors.email = "Email is in Valid"
}
if(isEmpty(data.password)){
errors.password = 'This fiels is required'
}
if(isEmpty(data.passwordConfirmation)){
errors.passwordConfirmation = 'This fiels is required'
}
if(!Validator.equals(data.password,data.passwordConfirmation)){
errors.passwordConfirmation = "Password Must Macthc"
}
if(isEmpty(data.timezone)){
errors.timezone = 'This fiels is required'
}
return{
errors,
isValid:isEmpty(errors)
}
}
router.post('/',(req,res) => {
console.log(req)
const {errors,isValid} = ValidateInput(req.body);
if(!isValid){
res.status(400).json(errors)
}
});
export default router
SignupForm.js
import React from 'react';
import timezones from '../../data/timezone';
import map from 'lodash/map';
class SignupForm extends React.Component {
constructor(props){
super(props);
this.state = {
username:'',
email:'',
password:'',
passwordConfirmation:'',
timezone:'',
errors:{}
};
this.onChange = this.onChange.bind(this);
this.onSubmit = this.onSubmit.bind(this)
}
onChange(e){
this.setState({ [e.target.name]:e.target.value })
}
onSubmit(e){
e.preventDefault();
this.setState({ errors:{} });
this.props.userSignupRequest(this.state).then(function (data) {
console.log(data)//Nothing
// this.setState({
// errors:data
// })
})
}
render(){
console.log(this.state)
const options = map(timezones,(val,key) =>
<option key={val} value={val}>{key}</option>
);
return(
<form onSubmit={this.onSubmit}>
<h1>Join our community</h1>
<div className="form-group">
<label className="control-label">Username</label>
<input
type="text"
name="username"
className="form-control"
value={this.state.username}
onChange={this.onChange}
/>
</div>
<div className="form-group">
<label className="control-label">Email</label>
<input
type="text"
name="email"
className="form-control"
value={this.state.email}
onChange={this.onChange}
/>
</div>
<div className="form-group">
<label className="control-label">Password</label>
<input
type="password"
name="password"
className="form-control"
value={this.state.password}
onChange={this.onChange}
/>
</div>
<div className="form-group">
<label className="control-label">passwordConfirmation</label>
<input
type="password"
name="passwordConfirmation"
className="form-control"
value={this.state.passwordConfirmation}
onChange={this.onChange}
/>
</div>
<div className="form-group">
<label className="control-label">Time Zone</label>
<select
className="form-control"
name="timezone"
onChange={this.onChange}
value={this.state.timezone}
>
<option value="" disabled>Choose Your Timezone</option>
{options}
</select>
</div>
<div className="form-group">
<button className="btn btn-primary btn-lg">
SignUp
</button>
</div>
</form>
)
}
}
SignupForm.propTypes ={
userSignupRequest:React.PropTypes.func.isRequired
};
export default SignupForm
You need to use catch... so
onSubmit(e){
e.preventDefault();
this.setState({ errors:{} });
this.props.userSignupRequest(this.state)
.then(function (data) {
//Success here
})
.catch(({response}) => console.log(response.data)) //Here you get your errors
})
}
I have some issue using asyncBlurFields in redux form, it just doesn't response,
container:
import React, { Component, PropTypes } from 'react'
import { connect } from 'react-redux'
import SupplierEditForm from '../../components/suppliers/SupplierEditForm'
import { reduxForm, change } from 'redux-form'
import { createSupplierRequest, updateSupplierRequest, fetchSupplierInfoRequest, validateSupplierRequest } from '../../api/suppliers'
import { resetSupplierForm, supplierFormSubmitSuccess } from '../../actions/SuppliersActions'
class SuppliersEditView extends Component {
constructor(props, context) {
super(props, context);
this.state = {isSubmitting: false}
}
componentWillMount() {
this.props.dispatch(resetSupplierForm())
}
componentDidMount() {
if(this.props.params.supplier_id) {
this.props.dispatch(fetchSupplierInfoRequest(this.props.params.supplier_id))
}
}
componentWillReceiveProps(nextProps) {
if(nextProps.supplier.isAction==true) {
if(!this.props.params.supplier_id) {
this.context.router.push('/suppliers/edit/'+nextProps.supplier.supplier_id)
} else {
this.props.dispatch(fetchSupplierInfoRequest(nextProps.supplier.supplier_id))
}
this.setState({isSubmitting:true})
setTimeout(() => {
this.hideStatus()
this.props.dispatch(supplierFormSubmitSuccess())
}, 1500)
}
}
hideStatus() {
this.setState({isSubmitting:false})
}
render() {
let pageHeader
if(this.props.fields.company_name.value) {
pageHeader = <h1 className="page-header">Suppliers - { this.props.fields.company_name.value }</h1>
}
else {
pageHeader = <h1 className="page-header">Suppliers</h1>
}
return (
<div className="container-fluid">
{pageHeader}
<SupplierEditForm
fields={this.props.fields}
handleSubmit={this.props.handleSubmit}
dispatchSupplier={this.props.dispatchSupplier.bind(this)}
supplier={this.props.supplier.payload}
isSubmitting={this.state.isSubmitting}
dispatchFieldChange={this.props.dispatchFieldChange}
supplier_id={this.props.params.supplier_id}
/>
</div>
)
}
}
const validateSupplier = (values, dispatch) => {
console.log('hi')
return new Promise((resolve, reject) => {
dispatch(validateSupplierRequest(values))
.then((response) => {
console.log(response)
});
})
}
const mapStateToProps = (state) => ({
supplier: state.suppliers.supplierInfo,
initialValues: state.suppliers.supplierInfo.payload
})
const mapDispatchToProps = (dispatch, props) => ({
dispatchSupplier: (values) => {
!props.params.supplier_id ? dispatch(createSupplierRequest(values)) : dispatch(updateSupplierRequest(values, props.params.supplier_id))
},
dispatchFieldChange: (field, value) => {
dispatch(change('SupplierEditForm',field,value))
}
})
SuppliersEditView.propTypes = {
asyncValidating: PropTypes.string.isRequired,
fields: PropTypes.object.isRequired,
resetForm: PropTypes.func.isRequired,
handleSubmit: PropTypes.func.isRequired,
submitting: PropTypes.bool.isRequired
}
SuppliersEditView.contextTypes = {
router: PropTypes.object
}
SuppliersEditView = reduxForm({
form: 'SupplierEditForm',
fields: ['company_logo','company_name', 'business_registration_no', 'mailing_address', 'billing_address', 'phone', 'email', 'fax', 'contact_person', 'contact_phone', 'contact_email', 'comments'],
asyncValidate: validateSupplier,
asyncBlurFields:['business_registration_no']
})(SuppliersEditView)
export default connect(mapStateToProps, mapDispatchToProps)(SuppliersEditView)
component:
import React, { Component } from 'react'
import { Link } from 'react-router'
import ReactDOM, { findDOMNode } from 'react-dom';
import { config } from '../../config'
import _ from 'lodash'
class SupplierEditForm extends Component {
constructor(props, context) {
super(props, context)
this.state = {
file: null,
imagePreviewUrl: null
}
}
handleImageChange(e) {
e.preventDefault();
let reader = new FileReader();
let file = e.target.files[0];
reader.onloadend = () => {
this.setState({
file: file,
imagePreviewUrl: reader.result
})
}
this.props.dispatchFieldChange(['company_logo'],file)
reader.readAsDataURL(file)
}
triggerImageUpload() {
ReactDOM.findDOMNode(this.refs.upload).click()
}
render () {
const { fields: { company_logo, company_name, business_registration_no, mailing_address, billing_address, phone, email, fax, contact_person, contact_phone, contact_email, comments }, handleSubmit, isSubmitting } = this.props
let imageSection
if(this.state.imagePreviewUrl) {
imageSection = <img src={this.state.imagePreviewUrl} width="100" onClick={this.triggerImageUpload.bind(this)}/>
} else if (_.isEmpty(this.props.supplier) || _.isNull(this.props.supplier.filename)){
imageSection = <div className="img-placeholder" onClick={this.triggerImageUpload.bind(this)}></div>
} else if (!_.isNull(this.props.supplier.filename) || !_.isEmpty(this.props.supplier)){
imageSection = <img src={config.FILE_DIR + this.props.supplier.filename} width="100" onClick={this.triggerImageUpload.bind(this)}/>
}
return (
<form onSubmit={handleSubmit(this.props.dispatchSupplier)} >
<button type="submit" disabled={isSubmitting} className="btn btn-primary mr8">
{
isSubmitting == true ?
<i className="fa fa-circle-o-notch fa-spin fa-fw"></i>
:
'Save'
}
</button>
<Link to="/suppliers" className="btn btn-secondary">Back</Link>
<div className="row">
{
isSubmitting ?
<div className="form-overlay"/>
: null
}
<div className="col-md-6">
<h2 className="mb24">Supplier details</h2>
<div className="form-group">
<label>Company logo</label>
<div className="col-md-12">
{imageSection}
</div>
<input type="file" ref="upload" className="col-xs-12 mb24 hide" {...company_logo} value={null} onChange={this.handleImageChange.bind(this)} />
</div>
<div className="form-group">
<label>Company name</label>
<input type="text" className="col-xs-12" {...company_name} required/>
</div>
<div className="form-group">
<label>Business registration no.</label>
<input type="text" className="col-xs-12" {...business_registration_no} required/>
</div>
<div className="form-group">
<label>Mailing address</label>
<input type="text" className="col-xs-12" {...mailing_address} required/>
</div>
<div className="form-group">
<label>Billing address</label>
<input type="text" className="col-xs-12" {...billing_address} required/>
</div>
<div className="form-group">
<label>Comments</label>
<textarea type="text" className="col-xs-12" {...comments} required></textarea>
</div>
</div>
<div className="col-md-6">
<h2 className="mb24">Contact details</h2>
<div className="form-group">
<label>Phone</label>
<input type="text" className="col-xs-12" {...phone} required/>
</div>
<div className="form-group">
<label>Fax</label>
<input type="text" className="col-xs-12" {...fax} required/>
</div>
<div className="form-group">
<label>Email</label>
<input type="email" className="col-xs-12" {...email} required/>
</div>
<div className="form-group">
<label>Contact person</label>
<input type="text" className="col-xs-12" {...contact_person} required/>
</div>
<div className="form-group">
<label>Contact phone</label>
<input type="text" className="col-xs-12" {...contact_phone} required/>
</div>
<div className="form-group">
<label>Contact email</label>
<input type="email" className="col-xs-12" {...contact_email} required/>
</div>
</div>
</div>
</form>
)
}
}
export default SupplierEditForm
However, whenever form is submitted, business_registration_no is suppose to respond on input lost focus, but it does not respond, have been trying for whole day. The weird thing is instead of firing this.props.dispatchSupplier when handleSubmit is invoked, it fires asyncValidate. Is there anything wrong in my code? Desperate for help!!
yep. need to use the Field-component and then also pass onBlur to that component..
like so :
https://github.com/erikras/redux-form/issues/1834
or so:
render() {
const { input: { value, onChange, onBlur }, meta: { touched, error } } = this.props
return (
<div>
<div className="example-class">
<input
type="tel"
className={this.inputFormClass(touched, error)}
autoComplete="on"
onChange={this.setPhoneNumber.bind(this)}
placeholder="some Placeholder"
onBlur={() => onBlur(value)}
/>
</div>
{this.showErrorMessage(touched, error)}
</div>
)
}