redux-form Validate only the fileds on selected tab content - reactjs

Is there a way to pass some initialvalue and update them when the tab is clicked and validate only a particular set of fields
import React, { Component } from 'react'
import { connect } from 'react-redux'
import {Field,reduxForm} from 'redux-form'
import { selectreport, decrementStep } from '../../actions.js'
class Step1 extends Component {
constructor (props) {
super(props)
this.handleChangeTab = this.handleChangeTab.bind(this)
this.stepBack = this.stepBack.bind(this)
}
stepBack (e) {
e.preventDefault()
console.log('reduce step by 1')
this.props.dispatch(decrementStep(this.props.step))
}
handleChangeTab (e) {
const { title: key } = e.target
console.log('click values are ', key)
this.props.dispatch(selectreport(key))
}
renderField(field){
const className = `row form-group ${field.meta.touched && field.meta.error ? 'has-error' : ''}`;
return(
<div className=" col-xs-12 col-md-offset-3 col-md-9">
<div className={className}>
<label className="col-xs-12 col-lg-12">{field.label}</label>
<input
type="text"
placeholder={field.placeholder}
className="form-control"
{...field.input} />
<div className="text-danger">
{field.meta.touched ? field.meta.error : ''}
</div>
</div>
</div>
);
}
onSubmit(values){
const { step, report } = this.props
}
render () {
const { step, report, parsedAddress,handleSubmit } = this.props
const { Line1, Line2} = parsedAddress
let st = JSON.stringify(step)
return (
<form className="" onSubmit={handleSubmit(this.onSubmit.bind(this))}>
<div className="">
<div className="row">
<div className="col-xs-10 col-md-6 col-xs-offset-1 col-md-offset-3">Enter details.</div>
</div>
<div className="row">
<div className="nav nav-pills col-xs-10 col-md-6 col-xs-offset-1 col-md-offset-3 PADD0">
<div className={report == 'address' ? ('col-xs-6 active') : 'col-xs-6'}>
<a data-toggle="tab" href="#address" title="address" onClick={this.handleChangeTab}>Address</a></div>
<div className={report == 'phone' ? 'col-xs-6 active' : 'col-xs-6'}>
<a data-toggle="tab" href="#phone" title="phone" onClick={this.handleChangeTab}>Phone</a></div>
</div>
</div>
<div className="row">
<div className="tab-content PADD20PX text-centered col-sm-offset-1 col-sm-10 col-md-offset-2 col-md-6 ">
<div id="address" className={report == 'address' ? 'tab-pane fade in PADD20PX active' : 'tab-pane fade in PADD20PX'}>
<Field
label="Address"
name="Line1"
placeholder="123 Sample Street"
component={this.renderField}
/>
<Field
label="address2"
name="Line2"
placeholder="APT"
component={this.renderField}
/>
</div>
<div id="phone" className={report == 'phone' ? 'tab-pane fade in PADD20PX active' : 'tab-pane fade in PADD20PX'}>
<Field
label="PhoneNumber"
name="phone"
placeholder="123.456.7890"
component={this.renderField}
/>
</div>
</div>
</div>
</div>
<div className="row PADDBOX">
<div className="col-xs-12">
<div className="pull-left">
<div className="pull-left">
<button type="button btn-rounded" onClick={this.stepBack} className="btn btn-default">Back</button>
</div>
</div>
<div className="pull-right"><button type="submit">Search</button></div>
</div>
</div>
</form>
</div>
)
}
}
function validate(values,props){
console.log("inside validate",props);
const errors = {};
if(!values.Line1){
errors.Line1 = "Enter address";
}
if(!values.Line2){
errors.Line2 = "Enter address";
}
if(!values.phone){
errors.phone = "Enter phone number";
}
return errors;
}
function mapStateToProps (state) {
return {
step: state.step,
parsedAddress: state.parsedAddress,
report: state.report
}
}
export default reduxForm({destroyOnUnmount: false,validate,form:'PostsnewForm'})(
connect(mapStateToProps)(Step1)
);
Have two tabs one for address and phone.
Trying to submit the form while on address tab, cant submit even if I pass all the validations since the validation on phone tab fails
Is there a way to pass a global state to the validate function and validate particular fields based on an attribute in global state.

Try this:
function validate(values) {
// console.log(values) -> {title: 'asdf', categories: 'asdf', content: 'asdf'}
const errors = {};
// validate the inputs from 'values'
if (!values.title || values.title.length < 3) {
errors.title = "Enter a title that is at least 3 characters!";;
}
// if errors is empty, the form is fine to submit
// If errors have any properties, redux form assumes form is invalid
return errors;
}
if (!values.categories) {
errors.categories = 'Enter some categories';
}
if (!values.content) {
errors.content = 'Enter some content, please';
}
export default reduxForm({
validate,
form: 'PostsNewForm'
})(PostsNew);
an if statement for the fields you do want to validate.

Related

React function Component Validation

I am a beginner in react. I was working on the react function component with forms using hooks. Can anyone please tell how can I apply validation on email text when it is invalid or empty, and disable the continue button if the form is not valid.
import React, { useState } from "react";
const ForgotPassowrd = () => {
const [emailId, setemailId] = useState("");
const forgotPasswordClick = (event) => {};
return (
<div>
<div className="NewPassword-form form_wrapper">
<div className="form-body">
<form action="#">
<div>
<div className="form-group">
<label htmlFor="password">Email-Id</label>
<div className="input-group">
<input type="text" className="form-control" value={emailId} onChange={(event)=>
setemailId(event.target.value)}/>
</div>
</div>
<button type="button" onClick={forgotPasswordClick} className="btn btn-lg
btn-block">Continue</button>
</div>
</form>
</div>
</div>
</div>
);
};
export default ForgotPassowrd;
**Try it.This may be helpfull for you! If you can any queries comment below.**
const LoginV2 = ({}) => {
// state
const [loginForm, setLoginForm] = useState({
email: undefined,
password: undefined,
emailValid: false,
passwordValid: false,
});
const [error, setError] = useState({ email: undefined, password: undefined });
// state update
const handleLoginForm = (e) => {
checkValidity(e.target.name, e.target.value);
setLoginForm({ ...loginForm, [e.target.name]: e.target.value });
};
// validation function
const checkValidity = (inputName, inputValue) => {
switch (inputName) {
case "email":
let pattern = /[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*#(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?/;
loginForm.emailValid = pattern.test(inputValue);
break;
case "password":
loginForm.passwordValid = inputValue.length >= 6;
break;
default:
break;
}
};
// form submit
const onSubmitLoginForm = () => {
console.log(loginForm);
if (!loginForm.emailValid) {
setError(prevError => {
return {
...prevError,
email: "Invalid Email Address"
}
});
}
if (!loginForm.passwordValid) {
setError(prevError => {
return {
...prevError,
password: "Password must be at least six characters long"
}
});
}
return (
<div class="row">
<div class="form">
<div class="col span-1-of-2">
<div class="username">
<p class="login-para text-align-center">LOG IN VIA EMAIL</p>
<form method="post" action="#" class="login-form">
{error.email && (
<div class="alert alert-danger">
<p>
{" "}
<strong> {alertText} </strong> {error.email}
</p>
</div>
)}
{error.password && (
<div class="alert alert-danger">
<p>
{" "}
<strong> {alertText} </strong> {error.password}
</p>
</div>
)}
<div class="info-box">
{icon && <i class="fas fa-user-alt login-icon"></i>}
<input
type="text"
name="email"
placeholder="Your Email"
onChangeText={(e) => handleLoginForm(e)}
inputValue={loginForm.email}
/>
</div>
<div class="info-box">
{icon && <i class="fas fa-user-alt login-icon"></i>}
<input
type="password"
name="password"
placeholder="Your Password"
onChangeText={(e) => handleLoginForm(e)}
inputValue={loginForm.password}
/>
</div>
<div class="buttons">
<input type="checkbox" />
<label class="remember" for="#">
Remember me
</label>
<div class="form-btn-disabled" onClick={onSubmitLoginForm}
>
LOGIN NOW
</div>
</div>
</form>
</div>
</div>
</div>
</div>
);
};
export default LoginV2;
Try below. I have added inline comments for better understanding. Comment your queries if you have any.
// Regex to check valid email
const validEmail = /^[\w-\.]+#([\w-]+\.)+[\w-]{2,4}$/g
import React, { useState } from "react";
const ForgotPassowrd = () => {
const [emailId, setemailId] = useState("");
//State to disable/enable continue button
const [disableBtn, setDisableBtn] = useState(false);
const forgotPasswordClick = (event) => {};
const handleSubmit = e => {
e.preventDefault();
// Do whatever you want to do after you click submit button
}
const handleChange = e => {
setemailId(event.target.value);
setDisableBtn(validEmail.test(e.target.value));
}
return (
<div>
<div className="NewPassword-form form_wrapper">
<div className="form-body">
{/* Remove action and use onSubmit handler*/}
<form onSubmit={handleSubmit}>
<div>
<div className="form-group">
<label htmlFor="password">Email-Id</label>
<div className="input-group">
{/* Introduced name attribute to help you with handleSubmit handler*/}
<input name="email" type="text" className="form-control" value={emailId} onChange={(event)=>
setemailId(event.target.value)}/>
</div>
</div>
<button onClick={forgotPasswordClick} className="btn btn-lg
btn-block" disabled={disableBtn}>Continue</button>
</div>
</form>
</div>
</div>
</div>
);
};
export default ForgotPassowrd;

why the component is getting unmounted and mounter everytime when the state is changed

Home.JS
class Home extends Component{
state = {
serverPosts:null,
offlinePosts:[],
isLoading:false,
isError:false,
error:null
}
componentDidMount(){
console.log("home did mount")
this.setState({isLoading:true})
axios.get('https://jsonplaceholder.typicode.com/posts')
.then((response)=>{
this.setState({
serverPosts:response.data,
isLoading:false
})
}).catch((err)=>{
this.setState({
isError:true,
error:err
})
})
}
addOfflinePost = (post) => {
const offlineList = [...this.state.offlinePosts,{post}]
this.setState({offlinePosts:offlineList})
}
render(){
console.log("Home component render")
let serverPostList = (this.state.serverPosts)?
this.state.serverPosts.map((item,index)=>{ return <Post postData = {item} key={index}/>}):
(this.state.isError)?<p>No Internet Connection</p>:<p>No Post available</p>
let offlinePostList = (this.state.offlinePosts)?
this.state.offlinePosts.map((item, index)=>{ return <Post postData = {item} key={`id-${index}`}/>}):<button className="btn btn-primary mx-auto" onClick={this.mainContentHandler}>Add Post</button>;
return(
<div className={classes.Home}>
<div className="row py-2">
<div className="col-lg-4">
<div className={"row "+ classes.OfflineList}>
</div>
<div className={"row "+ classes.ServerList}>
{serverPostList}
</div>
</div>
<div className="col-lg-8">
<PostForm click = {this.addOfflinePost}/>
</div>
</div>
</div>
)
}
}
export default Home;
AddForm.JS
class PostForm extends Component{
state = {
title:null,
content:null
}
titleChangeHandler = (event) => {
this.setState({title:event.target.value})
}
contentChangeHandler = (event) => {
this.setState({content:event.target.value})
}
render(){
return (
<div className="card card-primary">
<div className="card-header">
POST
</div>
<div className="card-body">
<form>
<div className="form-group">
<div className="form-group">
<input className="form-control" type="text" placeholder="Title" onChange={this.titleChangeHandler}/>
</div>
<div className="form-group">
<input className="form-control" type="text" placeholder="Content" onChange={this.contentChangeHandler}/>
</div>
<div className="form-group">
<button className="btn btn-primary btn-block" onClick={()=>this.props.click(this.state)}>Submit</button>
</div>
</div>
</form>
</div>
</div>
)}
}
export default PostForm;
Q1. The render function is running multiple times when the component get loaded. When i submit the form then the componentDidMount is running everytime. Please explain me how the flow is working in this component.
Q2. Also if you help me with the best practice of using bootstrap and manual styling together in react

Updating a list of options in the child when updating the parent state

My list of options (domains) based on the selected course is updated in the parent state, but the child won't update/inherit the prop sent with it. The child needs to receive the domains state from the parent and make up a option list out of it. It works on initialize, but won't update after the change of course in the parent component.
AddQuestion.js
class AddQuestion extends Component {
constructor(props){
super(props)
// initiate all states
this.state = {
course: '',
domains: []
}
}
render() {
return (
<MainQuestion formError={this.state.formError} levels={this.state.levels} years={this.state.years} courses={this.state.courses} introductionlist={this.state.introductionlist} subQuestions={this.state.subQuestions} numSubQuestion={this.state.numSubQuestion} handleCourseChange={this.handleCourseChange} postQuestion={this.postQuestion} addSubQuestion={this.addSubQuestion} formHasError={this.state.formHasError} validateForm={this.validateForm}/>
);
}
// handle onchange course input
handleCourseChange = (e) => {
this.setState({
course: e.target.value
},
function(e) {
console.log(this.state.course);
this.getResponseDomains();
},
this.validateForm(e)
);
}
// get domains based on course
getResponseDomains = () => {
console.log(this.state.course);
// fetch data from backend
axios.get('/api/domain/get?course=' + this.state.course, {
course: this.state.course
})
.then(response => response.data.data)
.then((json) => {
json.map(obj => this.setState({domains: Object.values(obj) }));
this.state.domains = json;
// map a option input for each fetched domain
let domainslist = Object.keys(this.state.domains).map(key =>
<option label={this.state.domains[key].name} value={this.state.domains[key].id} />
)
this.setState({
domains: domainslist
});
})
.catch((error) => {
console.log(error);
});
}
// Add the input field to a new subquestion
addSubQuestion = () => {
this.setState({
numSubQuestion: this.state.numSubQuestion + 1,
formHasError: true
});
//reset array
subQuestions = [];
let errormessages = '';
let errornum = this.state.numSubQuestion + 1;
//fill array for amount of subquestions needed
for (var i = 0; i <= this.state.numSubQuestion; i += 1) {
subQuestions.push(<SubQuestion key={i} number={i + 1} domain={this.state.domain} course={this.state.course} domains={this.state.domains} subjects={this.state.subjects} />);
this.setState({
subQuestions: subQuestions,
formError: errormessages
});
}
MainQuestion.js
// This is the main question (e.d. level, year, course and introduction)
class MainQuestion extends Component {
constructor(props){
super(props)
}
render() {
return (
<div className="addQuestion-wrapper">
<div className="logo mx-auto">
<img src="/img/logo-white.png"/>
</div>
<section className="addQuestion container">
<form id="addQuestionForm">
<p className="text-danger">{ this.props.formError }</p> {/* display errors */}
<div className="row d-flex prequestion">
<div className="col-12 mb-3">
<h2>Nieuwe vraag toevoegen</h2>
</div>
<div ref="error3" className="input-group col-12 col-lg-6" id="levels-wrapper">
<div>
<p className="label">Niveau</p>
{this.props.levels} {/* display fetched levels */}
</div>
</div>
<div ref="error4" className="input-group col-12 col-lg-6" id="years-wrapper">
<div>
<p className="label">Leerjaar</p>
{this.props.years} {/* display fetched years */}
</div>
</div>
<div ref="error5" className="input-group col-12 col-lg-6">
<p className="label">Vak</p>
<select onChange={this.props.handleCourseChange} name="course" id="select-courses">
<option value="" disabled selected>--Kies een vak</option>
{this.props.courses} {/* display fetched courses */}
</select>
</div>
<div ref="error10" className="input-group col-12 col-lg-12">
{this.props.introductionlist} {/* display created introduction textarea */}
</div>
</div>
{ this.props.subQuestions } {/* display amount of subquestions in the array */}
{/* add subquestion button */}
<div className="AddSubquestion">
<button className="btn" onClick={ this.props.addSubQuestion } disabled={this.props.formHasError}>Subvraag toevoegen</button>
</div>
{/* post question button */}
<div className="input-group" id="submit">
<button className="btn" onClick={ this.props.postQuestion } value="Aanmaken" disabled={this.props.formHasError}>Verzend</button>
</div>
</form>
</section>
</div>
);
}
}
export default AddQuestion;
SubQuestion.js
class SubQuestion extends Component {
constructor(props){
super(props)
// initiate all states
this.state = {
course: props.course,
domains: []
}
}
render() {
return (
<div className="row d-flex justify-content-center question mt-5">
<div className="col-12">
<h3> Subvraag {this.props.number} </h3> {/* display number of subquestion. Fetched from key of created child component */}
</div>
<div ref="error" className="input-group col-12 col-lg-6" id="type-wrapper">
{this.state.type} {/* display fetched type */}
</div>
<div ref="error2" className="input-group col-12 col-lg-6" id="questionings-wrapper">
<div>
<p className="label">Vraagstelling</p>
{this.state.questionings} {/* display fetched questionings */}
</div>
</div>
<div ref="error6" className="input-group col-12 col-lg-12">
{this.state.question} {/* display created textarea for questiona AND answer */}
</div>
<div ref="error7" className="input-group col-12 col-lg-6">
<p className="label">Domein</p>
<select id="select-domains" name={`domain-${this.props.number}`} onChange={this.handleDomainChange}>
<option value="" disabled selected>--Kies een domein</option>
{this.props.domains} {/* display fetched domains */}
</select>
</div>
<div ref="error8" className="input-group col-12 col-lg-6" id="select-subjects">
<p className="label">Onderwerp</p>
<select onChange={this.props.handleSubjectChange} name={`subject-${this.props.number}`}>
<option value="" disabled selected>--Kies een onderwerp</option>
{this.state.subjects} {/* display fetched subjects */}
</select>
</div>
<div ref="error9" className="input-group col-12 col-lg-12" id="time-points-rtti">
<div className="time mr-4">
{/* display time input */}
<p className="label">Tijdsduur</p>
<input type="number" name={`tijdsduur-${this.props.number}`} min="1" placeholder="tijd in minuten" onChange={this.props.handleTimeChange}/>
</div>
<div className="points mr-4">
{/* display points input */}
<p className="label">Punten</p>
<input type="number" name={`points-${this.props.number}`} min="1" placeholder="punten" onChange={this.props.handlePointsChange}/>
</div>
<div className="rtti">
{/* display rtti input */}
<p className="label">RTTI</p>
<input type="radio" name={`RTTI-${this.props.number}`} id={`R-${this.props.number}`} value="1" onChange={this.props.handleRttiChange}/><label htmlFor={`R-${this.props.number}`}>R</label>
<input type="radio" name={`RTTI-${this.props.number}`} id={`T1-${this.props.number}`} value="2" onChange={this.props.handleRttiChange}/><label htmlFor={`T1-${this.props.number}`}>T1</label>
<input type="radio" name={`RTTI-${this.props.number}`} id={`T2-${this.props.number}`} value="3" onChange={this.props.handleRttiChange}/><label htmlFor={`T2-${this.props.number}`}>T2</label>
<input type="radio" name={`RTTI-${this.props.number}`} id={`I-${this.props.number}`} value="4" onChange={this.props.handleRttiChange}/><label htmlFor={`I-${this.props.number}`}>I</label>
</div>
</div>
</div>
);
}
componentWillReceiveProps(nextProps) {
this.setState({course: nextProps.course, domains: nextProps.domains });
}
// handle onchange domain input
handleDomainChange = (e) => {
this.setState({
domain: e.target.value
},
this.getResponseSubjects, // change subjects based on selected domain
this.props.validateForm(e)
);
}
// get subjects based on domain
getResponseSubjects = () => {
// fetch data from backend
axios.get('/api/subject/get?domain=' + this.state.domain, {
domain: this.state.domain
})
.then(response => response.data.data)
.then((json) => {
json.map(obj => this.setState({subjects: Object.values(obj) }));
this.state.subjects = json;
// map a option input for each fetched subject
let subjectslist = Object.keys(this.state.subjects).map(key =>
<option label={this.state.subjects[key].name} value={this.state.subjects[key].id} />
)
this.setState({
subjects: subjectslist
}
);
})
.catch((error) => {
console.log(error);
});
}
export default SubQuestion;
The expected result would be the child component changing the domains based on the course. These variables are changed the parent AddQuestion, but don't come thru as prop in the child.
At first glance you're doing this:
handleCourseChange = (e) => {
this.setState({
course: e.target.value
},
function(e) {
console.log(this.state.course);
this.getResponseDomains();
},
this.validateForm(e)
);
}
If I'm right that callback after setState doesn't know what this is, because you're declaring a full function instead of an arrow function. Regular functions don't inherit this, they have it undefined by default.
I fixed it by calling the addSubQuestion function on handleCourseChange(). This forced the subquestions to re-render.

How to get the value from button group in react component

Below is the button group component which I used inside the form.How to implement the onchange functions to this button group.I have no Idea how to set the onchange method
import React, {Component} from "react";
import {Popover, OverlayTrigger} from 'react-bootstrap';
import "./ButtonGroup.scss";
const popoverBottom = () =>{
return (
<Popover className="tooltip-popover" title="Here is the where you
give a tooltip">
</Popover>
);
}
export const ButtonGroup = ({
tooltip,
label,
options,
selected,
lableStyle = {},
Title = "Tooltip on top",
}) => {
return (
<div className="nuclei-group">
<p className="nuclei-buttongroup-input"> {label} </p>
<div data-toggle="buttons">
{options.map((option, i) => {
const className = selected == option.value ? "active" : "";
return (
<label
key={i}
style={lableStyle}
className={`btn btn-default nuclei-selection-option ${className}`}
>
<input
type="radio"
name={"name"}
id={option.value}
autoComplete="off"
/>
{option.label}
</label>
);
})}
{tooltip ? (
<span>
<OverlayTrigger trigger="click" rootClose placement="bottom" overlay={popoverBottom()}>
<button type="button" className="btn nuclei-tooltip">?</button>
</OverlayTrigger>
</span>
) : null}
</div>
</div>
);
};
export default ButtonGroup;
then I tried to add on change as below and after submitting the form it doesn't work can somebody help me to resolve it.Normally inside a input tag it works but here? and let me know is this the best way to get values from a form as in the code below
import React, {Component} from "react";
import "./classic-quote.scss";
import {Button, ButtonGroup, InputText} from "../../../components";
import StepBreadcrumb from "../../../components/StepBreadcrumb";
import HeaderTitle from "../../../components/HeaderTitle";
import axios from 'axios';
export default class ClassicQuote extends Component {
constructor(props){
super(props);
this.state = {
insurance_type:'',
vehicle_registration:'',
lease_loan_hire:'',
estimated_market_value:'',
usage:'',
make:'',
model:'',
year:'',
claim_bonus_year:''
}
this.handleSubmit = this.handleSubmit.bind(this);
this.handleChange1 = this.handleChange1.bind(this);
this.handleChange2 = this.handleChange2.bind(this);
this.handleChange3 = this.handleChange3.bind(this);
this.handleChange4 = this.handleChange4.bind(this);
}
handleChange1(e){
this.setState({
make: e.target.value
})
}
handleChange2(e){
this.setState({
model: e.target.value
})
}
handleChange3(e){
this.setState({
year: e.target.value
})
}
handleChange4(e){
this.setState({
insurance_type: e.target.id
})
}
handleSubmit(e){
e.preventDefault();
const quotation = {
make: this.state.make,
model: this.state.model,
year: this.state.year,
insurance_type: this.state.insurance_type
}
console.log('gggggggg'+quotation.make+quotation.model+quotation.year+quotation.insurance_type);
let uri = '/items'
axios.post(uri,quotation).then(response => {
console.log('ela');
}).then(error => {
console.log(error);
});
}
render() {
return <div>
{/* <StepBreadcrumb id="bred" /> */}
<div className="container insureme-form zero-padding">
<form onSubmit={this.handleSubmit}>
<div className="row">
<HeaderTitle mainFirstWord="Insurance" restOfTitle="Detail" headerStyle={{fontWeight: "bold"}} headerIcon={true} />
<div className="nuclei-insurance-detail-step-one">
<div className="col-md-12 col-sm-12 col-xs-12">
<ButtonGroup onChange={this.handleChange4} label="" selected="full" options={[{label: "Full Insurance", value: "full"}, {label: "3rd Party Insurance", value: "3rd"}]} tooltip />
<pre>{JSON.stringify(this.state, '', 2)}</pre>
</div>
<div className="col-md-12 col-sm-12 col-xs-12">
<ButtonGroup label="Do you have a vehicle registration No?" selected="Yes" options={[{label: "Yes", value: "Yes"}, {label: "No", value: "No"}]} tooltip />
</div>
<div className="col-md-12 col-sm-12 col-xs-12">
<ButtonGroup label="Do you have any lease,Loan or hire on vehicle?" selected="Yes" options={[{label: "Yes", value: "Yes"}, {label: "No", value: "No"}]} tooltip />
</div>
<div className="col-md-4 col-sm-4 col-xs-8">
<InputText label={"Estimated Market Value?"} placeholder="Rs." />
</div>
<div className="col-md-12 col-sm-12 col-xs-12">
<ButtonGroup label="Usage?" selected="Private" options={[{label: "Private", value: "Private"}, {label: "Hire", value: "Hire"}, {label: "Rent", value: "Rent"}]} tooltip />
</div>
<div className="col-md-12 col-sm-12 col-xs-12 form-group input-text ">
<label>Make, Model and Year of Manufacture? </label>
<div className="col-md-4 col-sm-4 col-xs-4 zero-padding-left">
<input type="text" className="form-control" id={"make-manufacture"} placeholder={"Make"} onChange={this.handleChange1} />
</div>
<div className="col-md-3 col-sm-3 col-xs-4 zero-padding-left">
<input type="text" className="form-control" id={"model-manufacture"} placeholder={"Model"} onChange={this.handleChange2}/>
</div>
<div className="col-md-2 col-sm-2 col-xs-3 zero-padding-left">
<input type="text" className="form-control" id={"year-manufacture"} placeholder={"Year"} onChange={this.handleChange3}/>
</div>
</div>
<div className="col-md-12 col-sm-12 col-xs-12 form-group input-text">
<label>No Claims Bonus?</label>
<div className="col-md-4 col-sm-4 col-xs-8 zero-padding-left">
<InputText tooltip placeholder="No. of Years" />
</div>
</div>
<div className="col-md-12 col-sm-12 col-xs-12">
<Button type="submit" color="red" className="nuclei-bottom-red-button">
Get a Quick Quote
</Button>
<Button type="clear" color="gray" className="nuclei-bottom-gray-button">
Clear
</Button>
</div>
</div>
</div>
</form>
</div>
</div>;
}
}
I tried several ways can get only the make model and year values as printed in the console log
if you want to pass an handler like this:
onChange={this.handleChange4}
you have to add it to the props you receive in Component:
export const ButtonGroup = ({
onChange,
tooltip,
label,
options,
selected,
lableStyle = {},
Title = "Tooltip on top",
}) => {
...
and then in the input elements call onChange:
<input
onChange={onChange}
type="radio"
name={"name"}
id={option.value}
autoComplete="off"
/>
If you want to see the complete solution, I build it in sandbox: Full example here
I saw that you update the form, but you didn't add "onChange" in the ButtonGroup Component file like in the comment:
export const ButtonGroup = ({
onChange, <---this
tooltip,
label,
options,
selected,
lableStyle = {},
Title = "Tooltip on top",
}) => {
return (
<div className="nuclei-group">
<p className="nuclei-buttongroup-input"> {label} </p>
<div data-toggle="buttons">
{options.map((option, i) => {
const className = selected == option.value ? "active" : "";
return (
<label
key={i}
style={lableStyle}
className={`btn btn-default nuclei-selection-option ${className}`}
>
<input
onChange={onChange} <---this
type="radio"
name={"name"}
id={option.value}
autoComplete="off"
/>
{option.label}
</label>
);
})}

JSX not updating to binded State after await

I have a login form, which loads a loader when logging in. When login is unsucesful the loader should disappear and the buttons should reappear.
The loader is binded to this.state.loading.
if !this.state.loading it should show buttons (works on first load)
when this.state.loading = true then it should show loader (this works too)
I then run a promise using await async.
then I run this.state.loading = false and it does not update.
login.js:
import React, { Component } from "react";
import { connect } from "react-redux";
import * as actions from "../../actions";
import RoundLoader from "../elements/RoundLoader";
import Logo from "../img/image-center.png";
import "./login.css";
class Login extends Component {
constructor(props) {
super(props);
this.state = {
errorMsg: "",
loading: false
};
this.loginClicked = this.loginClicked.bind(this);
console.log("loggedIn:", this.props.login);
}
async loginClicked() {
try {
var self = this;
self.state.loading = true;
console.log("this1", this);
await this.props.loginUser(
this.refs.email.value,
this.refs.password.value
);
self.state.loading = false; //This has no effect on JSX
if (this.props.login.success) {
this.props.history.push("/");
}
} catch (ex) {
this.state.loading = false;
this.state.errorMsg = "Unable to connect to server";
console.log("error", ex);
}
}
render() {
return (
<div className="login-bg">
<div className="container signForm">
<div className="row back">
<i className="material-icons">arrow_back</i>
Back to Site
</div>
<div className="row login-container z-depth-4">
<div className="col s12 l6 image-bg">
<img className="hbi-logo" src={Logo} alt={"HBI Logo"} />
<h1 className="center-align">
Insurance <br /> Building Company
</h1>
</div>
<div className="col s12 l6 login-form">
<p className="center-align">Login to Trade Portal</p>
<form>
<div className="row">
<div className="input-field">
<input
id="email"
type="email"
className="validate"
ref="email"
/>
<label htmlFor="email">Email</label>
</div>
</div>
<div className="row">
<div className="input-field">
<input
id="password"
type="password"
className="validate"
ref="password"
/>
<label htmlFor="password">Password</label>
</div>
</div>
{!this.state.loading ? ( {/* HERE IS THE IF STATEMENT */}
/* If Not Loading then show Login buttons */
<div>
<div className="row">
<button
className="btn waves-effect waves-light"
type="button"
name="action"
onClick={this.loginClicked}
>
Submit
</button>
<a href="/subcontractor" className="register">
Register here
</a>
</div>
</div>
) : (
/* If Loading then show Loader not Login buttons */
<div className="row">
<div className="col s12 center">
<RoundLoader />
</div>
</div>
)}
<div className="row">
<div style={{ textAlign: "center", color: "red" }}>
{this.props.login.message}
</div>
</div>
</form>
</div>
</div>
</div>
</div>
);
}
}
function mapStateToProps({ login }) {
return { login };
}
export default connect(mapStateToProps, actions)(Login);
try
this.setState({loading: false})
instead of
this.state.loading = false;
https://reactjs.org/docs/react-component.html#setstate
From https://reactjs.org/docs/react-component.html#state :
Never mutate this.state directly, as calling setState() afterwards may replace the mutation you made. Treat this.state as if it were immutable.

Resources