Condtional Renderin React using If-else not working - reactjs

i'm new at React, i want to ask about contidional recndering, i'm making project about sending message, and i use validation to check all field is not empty, when one field is empty it should show error message that message not send. I using if-else to render the error message, but it doesn't work.
Here i add my code
....
export default class Message extends React.Component {
constructor(props){
super(props);
this.state = {
isLoggedIn: SystemStore.isLoggedIn(),
profile: ProfileStore.getProfile(),
fullName: SystemStore.systemUser().fullName,
site: '',
email: '',
phone: '',
subject: '',
description: '',
type: '',
errorMessage: '',
errorDialog: '',
isSubmited: false,
successMessage: '',
submitting: false
};
this.clearForm = this.clearForm.bind(this);
this.handleProfileChange = this.handleProfileChange.bind(this);
this.handleSubjectChange = this.handleSubjectChange.bind(this);
this.handleMessageChange = this.handleMessageChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.handleSubmitComplete = this.handleSubmitComplete.bind(this);
this.handleSubmitError = this.handleSubmitError.bind(this);
}
componentDidMount(){
ProfileStore.addProfileChangeListener(this.handleProfileChange);
if(!this.state.profile){
ProfileActions.reload()
}
MessageStore.addSubmitMessageChangeListener(this.handleSubmitComplete);
MessageStore.addSubmitMessageFailChangeListener(this.handleSubmitError);
}
componentWillUnmount(){
ProfileStore.removeProfileChangeListener(this.handleProfileChange);
MessageStore.removeSubmitMessageChangeListener(this.handleSubmitComplete);
MessageStore.removeSubmitMessageFailChangeListener(this.handleSubmitError);
}
render(){
return(
<Layout>
<div className='hs-dashboard row'>
<div className='col-md-12'>
<div className='col-xs-12 col-sm-6 col-md-5'>
<div className='col-xs-12 hs-message-form'>
<div className='row hs-message-form-head'>
<div className='hs-message-form-logo-container'>
<img className='col hs-message-form-logo' src='../../images/gii-logo-black.png'/>
<text className='hs-message-form-logo-label'>{T.translate('gii')}</text>
</div>
<div className='hs-message-form-label'>
{ T.translate('message.title') }
</div>
<div className='hs-message-form-label-1'>
{ T.translate('message.subtitle') }
</div>
</div>
<div className='row hs-message-form-body'>
<form className='hs-message-form-body-content'>
<label>
{ T.translate('message.type') }
</label>
<select
id="subject"
value={ this.state.subject }
onChange={ this.handleSubjectChange }
className="form-control"
required="true"
>
<option value="">{ T.translate('placeholder.selectSubject') }</option>
<option value="PRAYER">{ T.translate('message.pray') }</option>
<option value="ADDRESS">{ T.translate('message.address') }</option>
<option value="VISIT">{ T.translate('message.visit') }</option>
</select>
<label>
{T.translate('message.message')}
</label>
<textarea
type="text"
id="description"
className="form-control"
width=''
placeholder={ T.translate('placeholder.message') }
onChange={ this.handleMessageChange }
value={ this.state.description }
required
/>
{ this.state.errorDialog &&
<div className='hs-message-empty'>
{ this.state.errorDialog }
</div>
}
{ this.state.isSubmited === true ?
<div className='hs-message-success'>
{ this.state.successMessage }
</div> :
<div className='hs-message-error'>
{ this.state.errorMessage }
</div>
}
<LaddaButton
loading={ this.state.submitting }
onClick={ this.handleSubmit }
data-spinner-size={ 30 }
data-style={ SLIDE_RIGHT }
>
{ T.translate('action.send') }
</LaddaButton>
</form>
</div>
</div>
</div>
</div>
</div>
</Layout>
)
}
clearForm(){
this.setState({ subject: '', description: '' });
}
handleProfileChange(){
this.setState({
site: ProfileStore.getProfile().primarySite.name,
email: ProfileStore.getProfile().emailAddresses[0].email,
phone: ProfileStore.getProfile().contactNumbers[0].countryCode + ProfileStore.getProfile().contactNumbers[0].number
});
}
handleSubjectChange(evt){
this.setState({ subject: evt.target.value }, () => {
if(this.state.subject === 'PRAYER') {
this.setState({ type: 'REQUEST' });
} else if(this.state.subject === 'ADDRESS') {
this.setState({ type: 'INFORMATION' });
} else if(this.state.subject === 'VISIT'){
this.setState({ type: 'REQUEST' });
}
});
}
handleMessageChange(evt){
this.setState({ description: evt.target.value });
}
handleSubmit(evt) {
evt.preventDefault();
var errorDialog;
if(this.state.subject === ''){
errorDialog = 'Error:' + T.translate('msg.subjectRequired');
} else if(this.state.description === ''){
errorDialog = 'Error:' + T.translate('msg.mailDescriptionRequired');
}
this.setState({errorDialog: errorDialog});
this.handleProfileChange();
this.handleSubjectChange(evt);
this.handleMessageChange(evt);
var messageInfo = {
fullName: this.state.fullName,
site: this.state.site,
email: this.state.email,
phone: this.state.phone,
subject: this.state.subject,
description: this.state.description,
type: this.state.type
};
this.setState({ submitting: true }, () => {
MessageActions.sendMessage(messageInfo);
});
console.log(this.state.isSubmited);
}
handleSubmitComplete(){
this.setState({
submitting: false,
isSubmited: true,
errorMessage: null,
successMessage: T.translate('msg.mailSent')
});
this.clearForm();
}
handleSubmitError(){
this.setState({
submitting: false,
isSubmited: false,
errorMessage: T.translate('msg.mailSentFailed'),
successMessage: null
});
}
}
//updated code
This is my store.js
....
var MessageStore = assign({}, EventEmitter.prototype, {
emitSubmitMessageChange: function(){
this.emit(SUBMIT_MESSAGE);
},
addSubmitMessageChangeListener: function(callback){
this.on(SUBMIT_MESSAGE, callback);
},
removeSubmitMessageChangeListener: function(callback){
this.removeListener(SUBMIT_MESSAGE, callback);
},
emitSubmitMessageFailChange: function() {
this.emit(SUBMIT_MESSAGE_FAILED);
},
addSubmitMessageFailChangeListener: function(callback) {
this.on(SUBMIT_MESSAGE_FAILED, callback);
},
removeSubmitMessageFailChangeListener: function(callback) {
this.removeListener(SUBMIT_MESSAGE_FAILED, callback);
}
});
Dispatcher.register(function(action) {
switch(action.actionType){
case MessageConstants.PERFORM_SEND_MESSAGE:
MessageStore.emitSubmitMessageChange();
break;
case MessageConstants.PERFORM_SEND_MESSAGE_FAIL:
MessageStore.emitSubmitMessageFailChange();
break;
default:
//noop
}
})
export default MessageStore;
And this is my action.js
.....
function _sendMessage(messageInfo, callback) {
jQuery.ajax({
method: 'POST',
url: api('supportTickets'),
contentType: 'application/json',
data: JSON.stringify(messageInfo)
})
.done(function(messageInfo) {
callback(null, messageInfo);
})
.fail(function(err){
console.error('Failed to send message : ' + JSON.stringify(err));
callback(err, null);
});
}
var MessageActions = {
sendMessage: function(messageInfo) {
_sendMessage(messageInfo, function(err, messageInfo) {
if(err) {
Dispatcher.dispatch({
actionType: MessageConstants.PERFOM_SEND_MESSAGE_FAIL
});
}
Dispatcher.dispatch({
actionType: MessageConstants.PERFORM_SEND_MESSAGE,
messageInfo
});
});
}
};
module.exports = MessageActions;

Your form should be responsible for handling errors. You should know your errors at the time of submission of the form.
handleSubmit(evt) {
evt.preventDefault();
var errorDialog;
if(this.state.subject === ''){
errorDialog = 'Error:' + T.translate('msg.subjectRequired');
} else if(this.state.description === ''){
errorDialog = 'Error:' + T.translate('msg.mailDescriptionRequired');
}
if (errorDialog) {
this.setState({
// set your error here
})
return;
}
this.handleProfileChange();
this.handleSubjectChange(evt);
this.handleMessageChange(evt);
var messageInfo = {
fullName: this.state.fullName,
site: this.state.site,
email: this.state.email,
phone: this.state.phone,
subject: this.state.subject,
description: this.state.description,
type: this.state.type
};
this.setState({ submitting: true }, () => {
MessageActions.sendMessage(messageInfo);
});
console.log(this.state.isSubmited);
}

Your component seems to be a little complex. Think about breaking your component into smaller components. Using functional components I would do this task in a way something like that.
function validateForm() {
// validate form logic here. If it's ok, returns true, otherwise, returns false
}
function Message({ form }) {
if (!validateForm(form)) {
return (
<div>Please, fill the empty fields!!</div>
)
}
return (
<div>All good. Submit the form!!</div>
)
}

Related

React MenuItem event.target.value not working in one, but works for the other MenuItem

I have two MenuItem drop down menus. The first is for selecting between two items (not working) and the second drop down menu has a list of years, which is working.
The following are the functions that I have created to capture the event.target.value for each of them:
handleYrChange = (event) => {
console.log('handleYrChange: ' + event.target.value);
this.setState({ data: [] });
getPartIdUpperSa(event.target.value).subscribe((res) => {
this.setState({ data: res });
this.setState({ isLoading: false });
});
this.props.isLoading ? this.setState({ isLoading: false }) : this.setState({ isLoading: true });
this.setState({ yrValue: event.target.value });
this.onCloseYr();
}
handleSaChange = (event) => {
console.log('handleSaChange: ' + event.target.value);
if(event.target.value === 'notSa') {
this.setState({ isPartIdUpperSa: false });
} else {
this.setState({ isPartIdUpperSa: true });
}
setBaseUrl(event.target.value);
this.setState({ saValue: event.target.value });
this.onCloseSa();
}
handleYrClick = (event) => {
this.setState({ yrAnchorEl: event.target })
this.setState({ yrOpen: true });
}
handleSaClick = (event) => {
this.setState({ saAnchorEl: event.target })
this.setState({ saOpen: true });
}
The following is a screen shot of when I have tried to click on the items. As you can see, the drop down for years is working as expected, yet the other is capturing "0"
The following is the full component, along with the service that it is subscribed:
First the component:
import React from "react";
import { FormGroup, FormControl, Button, Menu, MenuItem } from '#material-ui/core';
import MUIDataTable from "mui-datatables";
import { MuiThemeProvider } from '#material-ui/core/styles';
import { getPartIdUpperSa } from '../services/part-id-upper-sa-service';
import { setBaseUrl } from '../services/part-id-upper-sa-service'
import theme from '../theme';
export default class ParIdUpperSaComponent extends React.Component {
state = {
data: [],
Header: [],
totalCount: 10,
options: {
pageSize: 16,
page: 0,
filterType: "dropdown",
selectableRows: false,
responsive: "scroll",
resizableColumns: true,
className: this.name,
textLabels: {
body: {
noMatch: this.props.isLoading ?
'' :
'Please wait while processing...',
},
},
},
divAnchorEl: null,
yrValue: '2020',
yrOpen: false,
yrAnchorEl: null,
yrs: [],
saValue: 'sa',
saOpen: false,
saAnchorEl: null,
sa: ["sa","notSa"],
isLoading: true,
isPartIdUpperSa: true
}
componentDidMount() {
// create array of years for the past 18 years
const currentYr = new Date().getFullYear();
for(let x = 0; x < 18; x++) {
this.state.yrs.push(currentYr - x );
}
this.subscription = getPartIdUpperSa().subscribe((res) => {
this.setState({ data: res });
this.props.isLoading ? this.setState({ textLabels: '' }) : this.setState({ textLabels: 'Please wait while processing...' });
this.setState({ isLoading: false });
this.setState({ Header: [
{
label: "Part ID",
name: 'part_id_upper',
options: {
className: 'first-col'
}
},
{
label: "Seq",
name: 'sequence',
options: {
className: 'sec-col'
}
},
{
label: "Qty",
name: 'quantity',
options: {
className: 'sm-col'
}
},
{
label: "Dt Orig",
name: 'date_originated',
options: {
className: 'mid-col'
}
},
{
label: "Div",
name: 'code_division',
options: {
className: 'sm-col'
}
},
]});
this.setState({
totalCount: Math.ceil(this.state.data.length / this.state.pageSize)
});
})
}
componentWillUnmount() {
// unsubscribe to ensure no memory leaks
this.subscription.unsubscribe();
}
handleYrChange = (event) => {
console.log('handleYrChange: ' + event.target.value);
// this.setState({value: event.target.value ? event.target.value : ''});
this.setState({ data: [] });
getPartIdUpperSa(event.target.value).subscribe((res) => {
this.setState({ data: res });
this.setState({ isLoading: false });
});
this.props.isLoading ? this.setState({ isLoading: false }) : this.setState({ isLoading: true });
this.setState({ yrValue: event.target.value });
this.onCloseYr();
}
handleSaChange = (event) => {
console.log('handleSaChange: ' + event.target.value);
if(event.target.value === 'notSa') {
this.setState({ isPartIdUpperSa: false });
} else {
this.setState({ isPartIdUpperSa: true });
}
setBaseUrl(event.target.value);
this.setState({ saValue: event.target.value });
this.onCloseSa();
}
handleYrClick = (event) => {
this.setState({ yrAnchorEl: event.target })
this.setState({ yrOpen: true });
}
handleSaClick = (event) => {
this.setState({ saAnchorEl: event.target })
this.setState({ saOpen: true });
}
onCloseYr = () => {
this.setState({ yrOpen: false });
}
onCloseSa = () => {
this.setState({ saOpen: false });
}
render() {
let arrayofSa = this.state.sa;
let saDropDown = arrayofSa.map((sa) =>
<MenuItem onClick={(event) => this.handleSaChange(event)} value={sa} key={sa}>
{sa}
</MenuItem>
);
let arrayOfYrs = this.state.yrs;
let yrDropDown = arrayOfYrs.map((yrs) =>
<MenuItem onClick={(event) => this.handleYrChange(event)} value={yrs} key={yrs}>
{yrs}
</MenuItem>
);
return (
<div>
<MuiThemeProvider theme={theme}>
<FormGroup column='true'>
<FormControl>
<Button aria-controls="simple-menu" aria-haspopup="true" onClick={this.handleSaClick}>
Select Sa or NotToSa
</Button>
<Menu id="sa-menu" open={this.state.saOpen}
anchorEl={this.state.saAnchorEl} onClose={this.onCloseSa}
defaultValue={this.state.saValue ? this.state.saValue : ''} >
{saDropDown}
</Menu>
<Button aria-controls="simple-menu" aria-haspopup="true" onClick={this.handleYrClick}>
Select Year
</Button>
<Menu id="yrs-menu" open={this.state.yrOpen}
anchorEl={this.state.yrAnchorEl} onClose={this.onCloseYr}
defaultValue={this.state.yrValue ? this.state.yrValue : ''} >
{yrDropDown}
</Menu>
</FormControl>
</FormGroup>
</MuiThemeProvider>
{this.state.isLoading ? <img src="ajax-loader.gif" alt="loading gif" /> : ''}
<MUIDataTable
title="Part ID Upper Sa / Not Sa Report"
data={ this.state.data }
columns={ this.state.Header }
options={ this.state.options }
/>
</div>
);
}
}
The following is the service:
import { ajax } from "rxjs/ajax";
import { Observable } from "rxjs";
let base_url = 'https://localhost:5001/PartIdUpperSa';
export const getBaseUrl = () => {
return base_url;
}
export const setBaseUrl = (param) => {
console.log("from within setBaseUrl: " + param);
if(param === 'notSa') {
base_url = 'https://localhost:5001/PartIdUpperNotSa';
} else {
base_url = 'https://localhost:5001/PartIdUpperSa';
}
}
let state = {
data: []
}
export const getPartIdUpperSa = (yr) => {
return new Observable(observe => {
let mYr = new Date().getFullYear();
let tempYr = (yr)? yr : mYr;
state.data = ajax
.get(base_url + "/" + tempYr)
.subscribe(resu => {
state.data = resu.response ;
// console.log("from within getPartIdUpperSa: " + JSON.stringify(resu.response));
observe.next(resu.response);
});
});
}
As usual, thanks in advance
I was able to find a work around. If someone could explain why this works, then I would appreciate it.
The component now uses numbers instead of characters in the array called "sa," which made it function as expected.
I used this:
sa: ["1","2"],
instead of this:
sa: ["sa","notSa"],
And it worked, the following is the complete component:
import React from "react";
import { FormGroup, FormControl, Button, Menu, MenuItem } from '#material-ui/core';
import MUIDataTable from "mui-datatables";
import { MuiThemeProvider } from '#material-ui/core/styles';
import { getPartIdUpperSa } from '../services/part-id-upper-sa-service';
import { setBaseUrl } from '../services/part-id-upper-sa-service'
import theme from '../theme';
export default class ParIdUpperSaComponent extends React.Component {
state = {
data: [],
Header: [],
totalCount: 10,
options: {
pageSize: 16,
page: 0,
filterType: "dropdown",
selectableRows: false,
responsive: "scroll",
resizableColumns: true,
className: this.name,
textLabels: {
body: {
noMatch: this.props.isLoading ?
'' :
'Please wait while processing...',
},
},
},
divAnchorEl: null,
yrValue: '2020',
yrOpen: false,
yrAnchorEl: null,
yrs: [],
saValue: '1',
saOpen: false,
saAnchorEl: null,
sa: ["1","2"],
isLoading: true,
isPartIdUpperSa: true
}
componentDidMount() {
// create array of years for the past 18 years
const currentYr = new Date().getFullYear();
for(let x = 0; x < 18; x++) {
this.state.yrs.push(currentYr - x );
}
this.subscription = getPartIdUpperSa().subscribe((res) => {
this.setState({ data: res });
this.props.isLoading ? this.setState({ textLabels: '' }) : this.setState({ textLabels: 'Please wait while processing...' });
this.setState({ isLoading: false });
this.setState({ Header: [
{
label: "Part ID",
name: 'part_id_upper',
options: {
className: 'first-col'
}
},
{
label: "Seq",
name: 'sequence',
options: {
className: 'sec-col'
}
},
{
label: "Qty",
name: 'quantity',
options: {
className: 'sm-col'
}
},
{
label: "Dt Orig",
name: 'date_originated',
options: {
className: 'mid-col'
}
},
{
label: "Div",
name: 'code_division',
options: {
className: 'sm-col'
}
},
]});
this.setState({
totalCount: Math.ceil(this.state.data.length / this.state.pageSize)
});
})
}
componentWillUnmount() {
// unsubscribe to ensure no memory leaks
this.subscription.unsubscribe();
}
handleYrChange = (event) => {
console.log('handleYrChange: ' + event.target.value);
this.setState({ data: [] });
getPartIdUpperSa(event.target.value).subscribe((res) => {
this.setState({ data: res });
this.setState({ isLoading: false });
});
this.props.isLoading ? this.setState({ isLoading: false }) : this.setState({ isLoading: true });
this.setState({ yrValue: event.target.value });
this.onCloseYr();
}
handleSaChange = (event) => {
console.log('handleSaChange: ' + event.target.value);
if(event.target.value === '2') {
this.setState({ isPartIdUpperSa: false });
} else {
this.setState({ isPartIdUpperSa: true });
}
setBaseUrl(event.target.value);
this.setState({ saValue: event.target.value });
this.onCloseSa();
}
handleYrClick = (event) => {
this.setState({ yrAnchorEl: event.target })
this.setState({ yrOpen: true });
}
handleSaClick = (event) => {
this.setState({ saAnchorEl: event.target })
this.setState({ saOpen: true });
}
onCloseYr = () => {
this.setState({ yrOpen: false });
}
onCloseSa = () => {
this.setState({ saOpen: false });
}
render() {
let arrayofSa = this.state.sa;
let saDropDown = arrayofSa.map((sa) =>
<MenuItem onClick={(event) => this.handleSaChange(event)} value={sa} key={sa}>
{sa}
</MenuItem>
);
let arrayOfYrs = this.state.yrs;
let yrDropDown = arrayOfYrs.map((yrs) =>
<MenuItem onClick={(event) => this.handleYrChange(event)} value={yrs} key={yrs}>
{yrs}
</MenuItem>
);
return (
<div>
<MuiThemeProvider theme={theme}>
<FormGroup column='true'>
<FormControl>
<Button aria-controls="simple-menu" aria-haspopup="true" onClick={this.handleSaClick}>
Select Sa or NotToSa
</Button>
<Menu id="sa-menu" open={this.state.saOpen}
anchorEl={this.state.saAnchorEl} onClose={this.onCloseSa}
defaultValue={this.state.saValue ? this.state.saValue : ''} >
{saDropDown}
</Menu>
<Button aria-controls="simple-menu" aria-haspopup="true" onClick={this.handleYrClick}>
Select Year
</Button>
<Menu id="yrs-menu" open={this.state.yrOpen}
anchorEl={this.state.yrAnchorEl} onClose={this.onCloseYr}
defaultValue={this.state.yrValue ? this.state.yrValue : ''} >
{yrDropDown}
</Menu>
</FormControl>
</FormGroup>
</MuiThemeProvider>
{this.state.isLoading ? <img src="ajax-loader.gif" alt="loading gif" /> : ''}
<MUIDataTable
title="Part ID Upper Sa / Not Sa Report"
data={ this.state.data }
columns={ this.state.Header }
options={ this.state.options }
/>
</div>
);
}
}
The following is the service that the component is subscribed to it:
import { ajax } from "rxjs/ajax";
import { Observable } from "rxjs";
let base_url = 'https://localhost:5001/PartIdUpperSa';
export const getBaseUrl = () => {
return base_url;
}
export const setBaseUrl = (param) => {
console.log("from within setBaseUrl: " + param);
if(param == '1') {
base_url = 'https://localhost:5001/PartIdUpperSa';
} else {
base_url = 'https://localhost:5001/PartIdUpperNotSa';
}
}
let state = {
data: []
}
export const getPartIdUpperSa = (yr) => {
return new Observable(observe => {
let mYr = new Date().getFullYear();
let tempYr = (yr)? yr : mYr;
state.data = ajax
.get(base_url + "/" + tempYr)
.subscribe(resu => {
state.data = resu.response ;
observe.next(resu.response);
});
});
}
Once more, if someone could explain why numbers work with event.target.value and characters do not, then I would appreciate it.

How to retrieve a react component value

I'm trying to make my own custom input[type='text'] on React, with my own effects.
To do that, I created my component:
Textbox.js
import React from "react";
class Textbox extends React.Component {
constructor(props) {
super();
this.state = {
inputValue: props.value,
fieldActive: false,
label: props.label,
placeholder: props.placeholder,
type: props.type,
maxLength: props.maxLength,
error: false,
required: props.required,
inputChange: props.onChange,
id: props.id,
valid: !props.required,
submitted: props.submitted,
_value: props.value,
updated: false
};
//console.log(this.props);
this.updateInputValue = this.updateInputValue.bind(this);
this.activateField = this.activateField.bind(this);
this.disableFocus = this.disableFocus.bind(this);
}
componentWillReceiveProps(nextProps) {
this.setState({
fieldActive: (nextProps.value != ''),
inputValue: nextProps.value
});
}
componentWillUpdate(nextProps, nextState) {
//console.log(nextState.inputValue);
if(/*this.state.inputValue != this.props.value*/ this.props.value != '' && !this.state.updated ){
this.setState({
inputValue: nextProps.value,//this.props.value,
updated: true,
fieldActive: true
});
}
}
componentDidUpdate(prevProps) {
//console.log('updating value: ' + prevProps.submitted);
if (this.props.submitted !== undefined) {
if (this.props.submitted !== prevProps.submitted) {
if(!this.state.required) return;
this.setState({
error: this.state.required && this.state.inputValue == ""
});
}
}
}
activateField() {
this.setState({
fieldActive: true
});
}
disableFocus(e) {
if (e.target.value == "") {
this.setState({
fieldActive: false,
error: this.state.required,
valid: !this.state.required
});
} else {
this.setState({
error: false
});
if (this.state.type == "email") {
this.setState({
error: !/^[a-zA-Z0-9]+#[a-zA-Z0-9]+\.[A-Za-z]+$/.test(e.target.value)
});
}
}
}
updateInputValue(e) {
//console.log('writing: ' + e.target.value);
this.setState({
inputValue: e.target.value,
submitted: false,
});
//this.props.value = e.target.value
if (this.state.inputChange != undefined && this.state.inputChange != null)
this.state.inputChange(e.target.id, e.target.value, this.state.valid);
this.activateField(e);
e.preventDefault();
}
render() {
return (
<div className="form-group field-group">
<label
htmlFor=""
className={
this.state.fieldActive
? this.state.error
? "field-active form-label floating error"
: "field-active form-label floating"
: "form-label floating hide"
}
>
{this.props.label}
</label>
<input
className={
this.state.error
? "form-input floating-label error"
: "form-input floating-label"
}
type={this.props.type}
placeholder={this.props.placeholder}
maxLength={this.props.maxLength}
value={this.state.inputValue}
name={this.props.id}
id={this.props.id}
autoComplete="off"
onFocus={this.activateField}
onBlur={this.disableFocus}
onChange={this.updateInputValue}
/>
<label
className={this.state.error ? "error" : "error hide"}
style={{ fontSize: 14, fontWeight: 400 }}
>
You must complete this field
</label>
</div>
);
}
}
export default Textbox;
myjsfile.js
constructor(props) {
super(props);
this.state = {
clients: [],
client: {
name: "",
},
};
//... More methods and properties
<Textbox
label="Client name"
placeholder="Client name / Customer"
id="name"
type="text"
required={true}
value={this.state.client.name}
maxLength="20"
//onChange={this.handleChange}
submitted={this.state.submitted}
/>
In my file, I'm using Textbox as a component, but each time that I want to retrieve the value inside the Textbox I get empty.
What am I doing wrong? Why the value is not updating? How can I solve it?

react update screen after changing values in the state

I am new to react and I am working on a project where I was ask to reset a form to its defaults.
I created a function that gets call after I click the reset button
<input id="reset_button"
type="button"
name="reset"
value="Reset"
onClick={this.resetSearch}/>
This is my function:
resetSearch: function() {
this.setState({ID: 'Moo'});
},
I do see the ID change value in the console but it does not update on the screen.
Other things that I have tried
# when I do this the element despairs from then screen
resetSearch: function() {
var values = this.fields.state.values;
this.setState({
defaultValues: {
values
},
ignoreDefault: false
});
}
#render function
render: function() {
return (
<div className="card-body with-padding-bottom-0">
<form id={this.formId}>
<div id="sn-fields" className="usa-grid-full sn-search">
<SNFields ref={(fields) => { this.fields = fields; }} ddl_id='sn_search_card_type' snOptions={ this.getProp('snOptions')} fields={this.getProp('fields')} updateParentState={this.updateStateByField} defaultFieldValues={this.getProp('defaultValues')} ignoreDefault={this.state.ignoreDefault}></SNFields>
</div>
<div className="usa-grid-full with-margin-top-10 validation-div">
<div id="sn_search_card_search_button_container" className="usa-width-one-whole">
<label htmlFor="system_validator"></label>
<input hidden name="system_validator" id="system_validator"/>
<input id="search_button" type="button" name="search" value="Search" onClick={this.personSearch}/>
<input id="reset_button" type="button" name="reset" value="Reset" onClick={this.resetSearch}/>
</div>
</div>
</form>
</div>
);
}
I was able to find a class SNFields
var SNFields = React.createClass({
filterFields: function(searchVal) {
console.log('PCQSFields - filterFields ')
var filterLabels = [];
//filter in this component since the filtering can't be done on the ruby side
switch(searchVal) {
case 'APPLICATION_ID':
case 'ENUMERATOR':
case 'ENCOUNTER_ID': {
filterLabels = ['ID'];
break;
}
case 'NAME_AND_DOB': {
filterLabels = ['Date of Birth', 'Last Name', 'Date Range', 'First Name'];
break;
}
default: {
break;
}
}
var fields = this.props.fields.slice();
for (var i = fields.length - 1; i > -1; i--) {
if (filterLabels.indexOf(fields[i].label) < 0) {
fields.splice(i, 1);
}
}
return fields;
},
render: function() {
console.log('NSFields - render ')
return (
<div>
<div className="usa-width-one-third">
<label htmlFor={this.props.ddl_id} className="card-label bold">Search Type</label>
<Dropdown id={this.props.ddl_id} onChange={this.updateFields} selectableArray={this.props.nsOptions} classes="" selectedOption={this.state.ddl}/>
</div>
<div className="flex-container" style={{'flexWrap': 'row'}}>
{this.nsFieldsHelper(this.state.fields)}
</div>
</div>
);
}
});
I guess what I really want to do is when I press the reset to call
SNFields.filterFields('NAME_AND_DOB')
but when I try that I get a message in the console that reads: Uncaught TypeError: NSFields.filterFields is not a function
How does your componentDidMount() and componentWillReceiveProps(newProps) look like?
This is how I have done an Input component:
import React, { Component } from 'react';
export default class Input extends Component {
displayName: 'Input';
constructor(props) {
super(props);
this.state = {
value: this.props.value,
disabled: this.props.disabled,
checked: this.props.checked,
className:this.props.className,
maxLength:this.props.maxLength,
placeholder:this.props.placeholder,
id:this.props.id,
name:this.props.name,
type:this.props.name,
oldValue:this.props.value,
backgroundColor:''
};
this.handleBlur = this.handleBlur.bind(this);
this.handleChange = this.handleChange.bind(this);
};
componentWillReceiveProps(nextProps) {
if (this.state.value !== nextProps.value) {
this.setState({ value: nextProps.value});
};
if (this.state.disabled !== nextProps.disabled) {
this.setState({ disabled: nextProps.disabled});
};
if (this.state.checked !== nextProps.checked) {
this.setState({ checked: nextProps.checked});
};
if (this.state.className !== nextProps.className) {
this.setState({ className: nextProps.className});
};
if (this.state.maxLength !== nextProps.maxLength) {
this.setState({ maxLength: nextProps.maxLength});
};
if (this.state.placeholder !== nextProps.placeholder) {
this.setState({ placeholder: nextProps.placeholder});
};
};
componentDidMount() {
this.setState({ value: this.props.value,
disabled: this.props.disabled,
checked: this.props.checked,
className:this.props.className,
maxLength:this.props.maxLength,
placeholder:this.props.placeholder
});
};
handleBlur(event) {
if ((this.props.checkError===null)||(this.props.checkError(event,false) === true)) {
this.setState({ value: event.target.value,
oldValue: event.target.value
})
}
else
{
this.setState({ value: this.state.oldValue })
}
this.setState({ backgroundColor: ''})
};
handleChange(event) {
if (this.state.value !== event.target.value) {
this.setState({ value: event.target.value })
if ((this.props.checkError!==null)&&(this.props.checkError(event,true) === false)) {
this.setState({ backgroundColor: 'red'})
}
else
{
this.setState({ backgroundColor: ''})
}
}
if (this.props.onClick!==null) {
this.props.onClick();
}
};
render() {
return <input value={this.state.value}
maxLength={this.state.maxLength}
placeholder={this.state.placeholder}
className={this.state.className}
id={this.props.id}
name={this.props.name}
type={this.props.type}
disabled={this.state.disabled}
checked={this.state.checked}
onBlur={this.handleBlur}
onChange={this.handleChange}
style={{background:this.state.backgroundColor}}/>
}
};
Input.propTypes=
{
value:React.PropTypes.string,
placeholder:React.PropTypes.string,
maxLength: React.PropTypes.number,
disabled:React.PropTypes.bool,
checked:React.PropTypes.bool,
className:React.PropTypes.string,
id:React.PropTypes.string,
name:React.PropTypes.string,
type:React.PropTypes.string,
checkError: React.PropTypes.func,
onClick: React.PropTypes.func
}
Input.defaultProps =
{
placeholder:'',
maxLength:100,
disabled:false,
checked:false,
value:'',
className:'',
id:'',
name:'',
type:'text',
checkError:null,
onClick:null
}

reset uncontrolled component content after submitting the form + react + jsx

I have a already built React form, which works fine expect reset functionality. It has used uncontrolled components bit different way. I am looking for what I need to follow, change the code to achieve my goal.
<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>
import * as React from "react";
import WidgetComponent from './../../lib/WidgetComponent';
import jQuery from 'jquery';
import InputListComponent from './components/InputListComponent';
import FormInputComponent from './components/FormInputComponent';
import formTextInputComponent from './components/formTextInputComponent';
import FormInputPasswordComponent from './components/FormInputPasswordComponent';
import FormSelectComponent from './components/FormSelectComponent';
import SubmitBtnListComponent from './components/SubmitBtnListComponent';
import SubmitBtnComponent from './components/SubmitBtnComponent';
import ErrorListBox from './components/ErrorListBox';
import EmailPromptModal from './components/EmailPromptModal';
import formHandlerInterfaceFactory from './lib/formHandlerInterface';
import formValidator from './lib/formValidators';
import {generateJQueryAjaxConfigFromPlaceholders} from './../../lib/GenerateJQueryAjaxConfig';
import './styles/registration-form.scss';
export default class ControlPanelCreateAccounts extends WidgetComponent {
constructor(props) {
super(props);
this.state = {
form: {
firstName: "",
lastName: "",
username: "",
password: "",
confirmPassword: "",
email: "",
phone: "",
accessLevel: -1,
},
userRoles: [],
validInputs: {
firstName: false,
lastName: false,
username: false,
password: false,
confirmPassword: false,
email: false,
phone: false,
accessLevel: false,
},
defaultValue: {
firstName: "",
lastName: "",
username: "",
password: "",
confirmPassword: "",
email: "",
phone: "",
accessLevel: -1,
},
errors: [],
submitService: null,
userRoleService: null,
newUserId: null,
};
this.onFormInputChange = this.onFormInputChange.bind(this);
this.onServicesCalled = this.onServicesCalled.bind(this);
this.onFormSubmit = this.onFormSubmit.bind(this);
this.formElementInvalid = this.formElementInvalid.bind(this);
this.formElementValid = this.formElementValid.bind(this);
this.postWidgetLoad = this.postWidgetLoad.bind(this);
this.createUserRequest = this.createUserRequest.bind(this);
this.createUserRoleRequest = this.createUserRoleRequest.bind(this);
this.onResetReceived = this.onResetReceived.bind(this);
this.onFormInputReset = this.onFormInputReset.bind(this);
}
onResetReceived(){
console.log('onResetReceived');
let newState = Object.assign(this.state.form, {
firstName : "",
});
this.setState(newState);
console.log(this.state.form);
}
postWidgetLoad(widget) {
EmailPromptModal.service = widget.services[2];//??
let submitService = widget.services[1];//1
let userRoleService = widget.services[2];//2
//this.storeState({ submitService });
let newState = Object.assign(this.state, {
submitService: submitService,
userRoleService: userRoleService
});
this.setState(newState);
}
validate() {
console.log('validating pre-submit');
let errors = Object.keys(this.state.validInputs).reduce((accum, current) => {
console.log('state of accumulator is: ');
console.log(accum);
console.log('current iteration is: ' + current);
//console.log('password and reType passwords are : ');
//console.log(this.state.form.password + " :: " + this.state.confirmPassword );
if (this.state.validInputs[current] === false) {
console.log('current input is invalid');
this.validate = this.validate.bind(this);
if (current === 'firstName') {
accum.push('The first name field is either empty or contains invalid characters');
}
if (current === 'lastName') {
accum.push('The last name field is either empty or contains invalid characters');
}
if (current === 'email') {
accum.push('The email field is empty or is not a valid email address');
}
if (current === 'phone') {
accum.push('The phone field is empty or is not a valid phone number');
}
if (current === 'password') {
accum.push('The password field is empty or contain less than 5 characters or contain invalid character');
}
if (current === 'confirmPassword') {
accum.push('The passwords mismatched');
}
if (current === 'accessLevel') {
accum.push('You must select a accessLevel from the drop-down menu.');
}
}
return accum;
}, []);
console.log('final error list looks like: ');
console.log(errors);
this.storeState({
errors: errors
});
return errors.length === 0;
}
onServicesCalled() {
let response = arguments[0][0].data;
let roleList = [];
if (response) {
response.map(element => {
roleList.push({val: element.id, text: element.role_name});
});
}
let newState = Object.assign(this.state, {
userRoles: roleList
});
this.setState(newState);
}
onFormInputChange(ev, legend) {
let value = ev.target.value;
let form = this.state.form;
form[legend] = value;
this.storeState({
form
});
formElementInvalid(elem) {
let name = elem.name;
let stateUpdateObj = this.state.validInputs;
stateUpdateObj[name] = false;
this.storeState({validInputs: stateUpdateObj});
if (name !== 'status') {
elem.classList.add('input-error');
} else {
document.getElementById('status-error-field').classList.add('visible');
}
}
formElementValid(elem) {
let name = elem.name;
let stateUpdateObj = this.state.validInputs;
stateUpdateObj[name] = true;
this.storeState({validInputs: stateUpdateObj});
if (name !== 'status') {
elem.classList.remove('input-error');
} else {
document.getElementById('status-error-field').classList.remove('visible');
}
}
onFormSubmit() {
if (this.validate()) {
console.log("validate got passed");
console.log(this.state.form);
var id;
// match password fields
if (this.state.form.password !== this.state.form.confirmPassword) {
let stateUpdateObj = this.state.validInputs;
stateUpdateObj['confirmPassword'] = false;
this.storeState({validInputs: stateUpdateObj});
this.onFormSubmit();
} else {
jQuery.when(this.createUserRequest()).done((r) => {
console.log("submit for createUser is success reload!");
console.log(r);
id = r.data.id;
jQuery.when(this.createUserRoleRequest(id)).done((r) => {
console.log("submit for createUserRole is success reload!");
console.log(r);
if(r.data.wasSuccessful){
console.log("create UserRole is successful, So reload the table ");
// do page refresh here
window.pubsub.publish('isp.reload-control-users', {});
//reset the form
console.log("reset the form contents");
this.onResetReceived();
}
}).fail((xhr, status, error) => {
console.log(status);
console.error(error);
alert('An error occured while submitting this request, if this issue persists please contact support.');
});
let newState = Object.assign(this.state, {
newUserId: r.data.id
});
this.setState(newState);
}).fail((xhr, status, error) => {
console.log(status);
console.error(error);
alert('An error occured while submitting this request, if this issue persists please contact support.');
});
}
}
}
//create a record in is_auth_roles table
createUserRoleRequest(id) {
let config = generateJQueryAjaxConfigFromPlaceholders(this.state.userRoleService, {'userId': id});
config.headers['Content-Type'] = 'application/json';
config.headers['Accept'] = '*/*';
config.data = JSON.stringify({
'roleId': this.state.form.accessLevel,
'type': 'add'
});
console.log("submit config of createUserRoleRequest() is: ");
console.log(config);
return jQuery.ajax(config);
}
createUserRequest() {
let config = generateJQueryAjaxConfigFromPlaceholders(this.state.submitService, {});
config.headers['Content-Type'] = 'application/json';
config.headers['Accept'] = '*/*';
config.data = JSON.stringify({
firstName: this.state.form.firstName,
lastName: this.state.form.lastName,
username: this.state.form.username,
phone: this.state.form.phone,
password: this.state.form.password,
confirmPassword: this.state.form.confirmPassword,
email: this.state.form.email,
accessLevel: this.state.accessLevel
});
console.log("submit config is: ");
console.log(config);
return jQuery.ajax(config);
}
render() {
return (
<div className="registration-form">
<h3 className="component-title"><i className="fa fa-table" aria-hidden="true"></i> User <span> Registration</span></h3><br/>
<InputListComponent>
{/*onValid={this.formElementValid} />*/}
<formTextInputComponent legend="firstName" label="First Name" placeholder="First Name" onChange={this.onFormInputChange} validator={formValidator.nameValidator} onInvalid={this.formElementInvalid} default = {this.state.defaultValue.firstName} value={ this.state.value}
onValid={this.formElementValid} />
<FormInputComponent legend="lastName" label="Last Name" placeholder="Last Name" onChange={this.onFormInputChange} validator={formValidator.nameValidator} onInvalid={this.formElementInvalid} default = {this.state.defaultValue.lastName}
onValid={this.formElementValid}/>
<FormInputComponent legend="username" label="User Name" placeholder="User Name" onChange={this.onFormInputChange} validator={formValidator.nameValidator} onInvalid={this.formElementInvalid} default = {this.state.defaultValue.username}
onValid={this.formElementValid}/>
<FormInputPasswordComponent legend="password" label="Password" placeholder="Password" onChange={this.onFormInputChange} validator={formValidator.passwordValidator} onInvalid={this.formElementInvalid} default = {this.state.defaultValue.password}
onValid={this.formElementValid}/>
<FormInputPasswordComponent legend="confirmPassword" label="Confirm Password" placeholder="Confirm Password" onChange={this.onFormInputChange} validator={formValidator.passwordValidator} default = {this.state.defaultValue.confirmPassword}
onInvalid={this.formElementInvalid} onValid={this.formElementValid}/>
<FormInputComponent legend="email" label="Email Address" placeholder="Email" onChange={this.onFormInputChange} validator={formValidator.emailValidator} onInvalid={this.formElementInvalid} default = {this.state.defaultValue.email}
onValid={this.formElementValid}/>
<FormInputComponent legend="phone" label="Phone Number" placeholder="Phone Number" onChange={this.onFormInputChange} validator={formValidator.phoneValidator} onInvalid={this.formElementInvalid} default = {this.state.defaultValue.phone}
onValid={this.formElementValid}/>
<FormSelectComponent legend="accessLevel" data={this.state.userRoles} onChange={this.onFormInputChange} validator={formValidator.statusValidator} onInvalid={this.formElementInvalid} default = {this.state.defaultValue.accessLevel}
onValid={this.formElementValid}/>
</InputListComponent>
<ErrorListBox errorList={this.state.errors}/>
<button className="dataTable-modal-btn click-btn" onClick={this.onFormSubmit}>CREATE USER</button>
</div>
);
}
}
window.ControlPanelCreateAccounts = ControlPanelCreateAccounts;
window.CurrentWidget = window.ControlPanelCreateAccounts;
this is formInputComponent code
<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>
const FormInputComponent = (props) => {
const onChangeHandler = (ev) => {
if(props.validator(ev.target.value)) {
props.onChange(ev, props.legend);
props.onValid(ev.target);
} else {
props.onInvalid(ev.target);
}
};
console.log('props.defaultValue');
console.log(props.legend);
console.log(props.default);
console.log(props.value);
return (
<div className="form-row">
<label>{props.label}</label><br />
<input name={props.legend} type="text" placeholder={props.placeholder} onChange={onChangeHandler} defaultValue={props.default || ''} value={props.value}/>
</div>
);
};
FormInputComponent.propTypes = {
legend: React.PropTypes.string,
label: React.PropTypes.string,
placeholder: React.PropTypes.string,
onChange: React.PropTypes.func,
validator: React.PropTypes.func,
onInvalid: React.PropTypes.func,
onValid: React.PropTypes.func,
default: React.PropTypes.string,
};
export default FormInputComponent;
If you want setState inside of onResetReceived to reset the form, you'll need to set the value prop of each form field. The default prop gets sent to FormInputComponent as the defaultValue of the input, but you can also see it accepts a value={props.value} as well (even though value is not defined in its PropTypes. From the parent set
<FormInputComponent value={this.state.form.firstName} ... />
This will ensure changing this.state.form via setState will update each form field.

Update select react from another select option

I'm trying to update my city select from the selected state, but the city does not update when I change the state:
Here is the part of my render code:
<div>
<label for="state">state:</label>
<SelectInput items="RO-DF-RS-SP-RJ-MG-PR" onChange={this.handleChange} name="state"/>
</div>
{!!this.state.stt &&
(
<div>
<label for="city">city:</label>
<SelectInput url="/static/json/" filename={this.state.stt} onChange={this.props.onChange} name="city"/>
</div>
)
}
<div>
this.props.onChange is just a handler to get the value of the input to save the data at database
And the code:
handleChange(event){
if(event.target.name == "state"){
this.setState({
stt: event.target.value
});
}
if(this.props.onChange) {
this.props.onChange(event);
}
}
sets the correct state (this.state.stt)
Here is my SelectInput:
class SelectInput extends React.Component{
constructor(props){
super(props);
this.state = {
select: "",
items: [],
filename: this.props.filename
}
this.handleChange = this.handleChange.bind(this)
}
componentDidMount(){
if(this.props.filename){
console.log(this.props.filename);
}
if(this.props.items){
this.setState({
items: this.props.items.split("-")
})
}
else if(this.props.url && this.props.filename){
$.ajax({
type: 'GET',
url: `${this.props.url}${this.props.filename}.json`,
headers: { 'Authorization': "Token " + localStorage.token },
success: (result) => {
this.setState({
items: result.child
})
},
error: function (cb) { console.log(cb) }
});
}
}
handleChange(event){
this.setState({
select: event.target.value
});
if(this.props.onChange) {
this.props.onChange(event)
}
}
render(){
return (
<select name={this.props.name} value={this.state.select} onChange={this.handleChange}>
<option value=""></option>
{this.state.items && this.state.items.map(item =>
<option value={item}>{item}</option>
)}
</select>
)
}
}
export default SelectInput
Any idea to solve my problem?
Since you are setting filename dynamically you need to implement componentWillReceiveProps that will make ajax request to load new file.
componentWillReceiveProps({ filename }) {
if(filename !== this.props.filename) {
this.loadItems(filename)
}
}
loadItems(filename) {
$.ajax({
type: 'GET',
url: `${this.props.url}${filename}.json`,
headers: {
'Authorization': "Token " + localStorage.token
},
success: (result) => {
this.setState({
items: result.child
})
},
error: function(cb) {
console.log(cb)
}
});
}

Resources