Validation in React To-do app - javascript

I have simple to-do app and trying to do validation for adding new task mainly I want to prevent user to add a blank task to the list - my React skills are very poor so please forgive this silly question.
if you have any idea how to solve my problem please let me know thanks!
import React, { Component } from 'react';
import AppBar from 'material-ui/AppBar';
import Toolbar from 'material-ui/Toolbar';
import Typography from 'material-ui/Typography';
import Paper from 'material-ui/Paper';
import Grid from 'material-ui/Grid';
import TextField from 'material-ui/TextField';
import List from './List';
import '../App.css';
class App extends Component {
state = {
query: '',
inputValue: '',
todos: [
{ value: 'Naumiej się Reacta', done: false },
{ value: 'Pucuj trzewiki ', done: true },
],
direction: 'row',
justify: 'left',
alignItems: 'left',
}
handleChange = (evt) => {
this.setState({ inputValue: evt.target.value });
}
removeMe = (index) => {
this.setState({
todos: this.state.todos.filter((_, i) => i !== index)
})
}
searchChanged = (evt) => {
this.setState({ query: evt.target.value })
}
handleSubmit = (evt) => {
if (evt.keyCode === 13) {
const newTodo = {
value: this.state.inputValue,
done: false
};
const todos = this.state.todos.concat(newTodo);
this.setState({ todos: todos, inputValue: '' })
}
}
render() {
return (
<Grid item xs={12} style={{ padding: 30, display: 'flex' }}>
<div className="App">
<Typography type="body1'" color="inherit" text-align='left'>
<AppBar position="static" color="default" style={{ flexDirection: 'center' }}>
<Toolbar>
<TextField
style={{ float: 'left', paddingRight: 40, }}
placeholder="Add Task ..."
onChange={this.handleChange}
inputValue={this.state.inputValue}
onKeyDown={this.handleSubmit}
>
</TextField>
<TextField ype="text" placeholder="Search..." onChange={this.searchChanged} />
</Toolbar>
</AppBar>
</Typography>
<Paper>
<List style={{ marginTop: 90 }}
removeMe={this.removeMe}
todos={this.state.todos}
query={this.state.query}
/>
</Paper>
</div>
</Grid>
);
}
}
export default App;

I think you did correctly. Just return before submit or check for value with enter key.
handleSubmit = (evt) => {
if (evt.keyCode === 13 && this.state.inputValue) {
const newTodo = {
value: this.state.inputValue,
done: false
};
const todos = this.state.todos.concat(newTodo);
this.setState({todos: todos, inputValue: ''})
}
}

Related

How can I pass values or fields from one page to another page in ReactJS?

How can I send the value of the checkbox to the checkout.js page? This is the PaymentForm page. I tried my best but it's not working correctly. Basically, I want to use the PaymentForm fields in checkout.js page because my submit button is there.
PaymentForm.js
import React from 'react';
import Typography from '#material-ui/core/Typography';
import Grid from '#material-ui/core/Grid';
import TextField from '#material-ui/core/TextField';
import FormControlLabel from '#material-ui/core/FormControlLabel';
import Checkbox from '#material-ui/core/Checkbox';
import { createStyles } from '#material-ui/core/styles';
import StripeCheckout from 'react-stripe-checkout'
import 'react-toastify/dist/ReactToastify.css';
const styles = createStyles({
formControlLabel: {
fontSize: '1.5rem',
'& label': { fontSize: '5rem' }
}
});
const handleToken = (token) => {
console.log(token);
}
const PaymentForm = ({ PaymentForm, changePaymentForm }) => {
const [state, setState] = React.useState({
checkedA: false,
});
const handleChange = (event) => {
setState({ ...state, [event.target.name]: event.target.checked });
};
return (
<React.Fragment>
<Typography variant="h4" gutterBottom>
Payment method
</Typography><br />
<Grid container spacing={3}>
<Grid item xs={12}>
<FormControlLabel
control={<Checkbox checked={state.checkedA} onChange={handleChange} name="checkedA"/>}
label={<Typography style={styles.formControlLabel}>Cash on delivery</Typography>}
/>
</Grid>
<Grid item xs={12}>
<StripeCheckout
stripeKey="pk_test_51I9XPQAesAg2GfzQyVB7VgP0IbmWwgcfeFJSuCpB2kbNu60AFTbFhC7dxwje8YF4w2ILMJ6o2InB9ENczpd4dCSa00e09XoDbw"
token={handleToken}
amount={2 * 100}
name="All Products"
/>
</Grid>
</Grid>
</React.Fragment>
);
};
export default PaymentForm;
Checkout.js
import React from 'react';
import { makeStyles } from '#material-ui/core/styles';
import CssBaseline from '#material-ui/core/CssBaseline';
import AppBar from '#material-ui/core/AppBar';
import Toolbar from '#material-ui/core/Toolbar';
import Paper from '#material-ui/core/Paper';
import Stepper from '#material-ui/core/Stepper';
import Step from '#material-ui/core/Step';
import StepLabel from '#material-ui/core/StepLabel';
import Button from '#material-ui/core/Button';
import Link from '#material-ui/core/Link';
import Typography from '#material-ui/core/Typography';
import axios from '../../axios-orders';
import AddressForm from './CheckoutForm';
import PaymentForm from './PaymentForm';
import Review from './Review';
const useStyles = makeStyles((theme) => ({
appBar: {
position: 'relative',
},
layout: {
width: 'auto',
marginLeft: theme.spacing(2),
marginRight: theme.spacing(2),
[theme.breakpoints.up(1000 + theme.spacing(2) * 2)]: {
width: 1100,
marginLeft: 'auto',
marginRight: 'auto',
},
},
paper: {
marginTop: theme.spacing(3),
marginBottom: theme.spacing(3),
padding: theme.spacing(2),
[theme.breakpoints.up(700 + theme.spacing(3) * 2)]: {
marginTop: theme.spacing(6),
marginBottom: theme.spacing(6),
padding: theme.spacing(3),
backgroundColor: 'rgb(248, 246, 244)',
},
},
stepper: {
padding: theme.spacing(5, 0, 5),
fontWeight: 'bold',
backgroundColor: 'rgb(248, 246, 244)',
},
buttons: {
display: 'flex',
justifyContent: 'flex-end',
},
button: {
marginTop: theme.spacing(3),
marginLeft: theme.spacing(1),
border: "none"
},
}));
const steps = ['Shipping address', 'Payment details', 'Review your order'];
function Copyright() {
return (
<Typography variant="body2" color="textSecondary" align="center">
{'Copyright © '}
<Link color="inherit" href="https://material-ui.com/">
Your Website
</Link>{' '}
{new Date().getFullYear()}
{'.'}
</Typography>
);
}
function getStepContent(step, formValues = null, changeFormValue = null, paymentValues = null, changePaymentValue = null) {
switch (step) {
case 0:
return <AddressForm addressValues={formValues} changeAddressValue={changeFormValue} />;
case 1:
return <PaymentForm PaymentForm={paymentValues} changePaymentForm={changePaymentValue}/>;
case 2:
return <Review />;
default:
throw new Error('Unknown step');
}
}
export default function Checkout(props) {
const classes = useStyles();
const [addressFormValues, setAddressFormValues] = React.useState({});
const [paymentFormValues, setPaymentFormValues] = React.useState({});
const [paymentFormNewValues, setPaymentFormNewValues] = React.useState({});
const [activeStep, setActiveStep] = React.useState(0);
if(paymentFormValues === true){
setPaymentFormNewValues('Cash')
}
if(paymentFormValues === false){
setPaymentFormNewValues('Online')
}
console.log('[paymentFormNewValues: ]', paymentFormNewValues)
console.log('[paymentFormValues: ]', paymentFormValues)
const handleNext = () => {
setActiveStep(activeStep + 1);
axios.post('/UserPortal/CartItems/checkout_details_check.php', {
customer_id: localStorage.getItem('Id'),
})
.then((response) => {
if(response.data === null)
{
axios.post('/UserPortal/CartItems/checkout_details.php', {
customer_id: localStorage.getItem('Id'),
firstname: addressFormValues.firstname,
lastname: addressFormValues.lastname,
address: addressFormValues.address,
city: addressFormValues.city,
state: addressFormValues.state
})
.then((response) => {
console.log(response.data);
})
}
else{
axios.post('/UserPortal/CartItems/checkout_details_update.php', {
customer_id: localStorage.getItem('Id'),
firstname: addressFormValues.firstname,
lastname: addressFormValues.lastname,
address: addressFormValues.address,
city: addressFormValues.city,
state: addressFormValues.state,
payment_method: paymentFormNewValues
})
.then((response) => {
console.log(response.data);
})
}
})
};
const handleBack = () => {
setActiveStep(activeStep - 1);
};
const changeAddressFormValue = (key, value) => {
let values = { ...addressFormValues };
values[key] = value;
setAddressFormValues(values);
};
const changePaymentFormValue = (key, value) => {
let values = { ...addressFormValues };
values[key] = value;
setPaymentFormValues(values);
};
return (
<React.Fragment>
<CssBaseline />
<AppBar position="absolute" color="default" className={classes.appBar}></AppBar>
<main className={classes.layout}>
<Paper className={classes.paper}>
<Typography component="h1" variant="h3" align="center">
Checkout
</Typography>
<Stepper activeStep={activeStep} className={classes.stepper}>
{steps.map((label) => (
<Step key={label}>
<StepLabel><Typography component="h1" variant="h5" align="center">
{label} </Typography></StepLabel>
</Step>
))}
</Stepper>
<React.Fragment>
{activeStep === steps.length ? (
<React.Fragment>
<Typography variant="h5" gutterBottom>
Thank you for your order.
</Typography>
<Typography variant="subtitle1">
Your order number is #2001539. We have emailed your order
confirmation, and will
send you an update when your order has shipped.
</Typography>
</React.Fragment>
) : (
<React.Fragment>
{activeStep === 0 ? getStepContent(activeStep, addressFormValues, changeAddressFormValue , paymentFormValues, changePaymentFormValue) : getStepContent(activeStep)}
{ <div className={classes.buttons}>
{ activeStep !== 0 && (
<Button variant="contained" style={{outline: 'none'}}
className={classes.button}
onClick={handleBack}
>
Back
</Button>
)}
<Button style={{outline: 'none'}}
variant="contained"
color="secondary"
onClick={handleNext}
className={classes.button}
>
{activeStep === steps.length - 1 ? 'Place order' : 'Next'}
</Button>
</div> }
</React.Fragment>
)}
</React.Fragment>
</Paper>
<Copyright />
</main>
</React.Fragment>
);
}
It seems you have checked the activeStep wrong.
Maybe the right code must be like the following:
<React.Fragment>
{activeStep !== 0 ?getStepContent(activeStep, addressFormValues, changeAddressFormValue , paymentFormValues, changePaymentFormValue) : getStepContent(activeStep)}
Do you ever consider using Context API?
React Context API
But also you can use create a checkboxValue with useState in Checkout.js and pass setCheckBoxValue to PaymentForm in getStepContent as prop. When checkbox checked trigger setCheckBoxValue and it will trigger parent component's state (Checkbox).

Reactjs Parent not getting child data change values. Rerender issue

I need to update Parent table when data is changed from child edit form. Not getting the updated data in parent component.
I'm passing the data using all the passible ways as per my understanding. I'm not much experienced in react. So it would be really very helpful if someone can help me to understand where i'm making mistake.
PARENT Component is class component-
import Radium from 'radium';
import Dock from 'react-dock';
import {Divider} from '#material-ui/core';
import "react-tabulator/lib/styles.css";
import "react-tabulator/css/bootstrap/tabulator_bootstrap.min.css";
import { React15Tabulator, reactFormatter, MultiValueFormatter } from "react-tabulator";
import {Badge, Row, Button, Col,Card} from 'react-bootstrap';
import EditServer from '../EditServer';
import Confirm from '../../../ui-components/Confirm';
// import './index.scss';
import jsondata from '../../../constants/data/json/ApplicationServer.json';
const styles = {
root: {
fontSize: '16px',
color: '#999',
height: '100vh',
},
main: {
width: '100%',
height: '100%',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
paddingTop: '30vh',
},
dockContent: {
// width: '400px',
height: '100%',
display: 'flex',
alignItems: 'left',
padding:'1rem',
overflowX:"hidden",
// justifyContent: 'center',
flexDirection: 'column',
},
remove: {
position: 'absolute',
zIndex: 1,
right: '10px',
top: '10px',
cursor: 'pointer'
}
}
const positions = ['left', 'top', 'right', 'bottom'];
const dimModes = ['transparent', 'none', 'opaque'];
// const dimStyle = ['all']
function SimpleBage (props: any) {
const rowData = props.cell._cell.row.data;
const cellValue = props.cell._cell.value || 'STANDALONE | DOWN | PRIMARY | BACKUP';
if(cellValue === 'STANDALONE'){
return <h5><Badge pill variant="warning" className="btn-size"
onClick={() => alert(rowData.serverStatus)}>
{cellValue}</Badge></h5>;
}
else if(cellValue === 'DOWN'){
return <h5><Badge pill variant="dark" className="btn-size">
{cellValue}</Badge></h5>;
}
else if(cellValue === 'PRIMARY'){
return <h5><Badge pill variant="success" className="btn-size">
{cellValue}</Badge></h5>;
}
else if(cellValue === 'BACKUP'){
return <h5><Badge pill variant="primary" className="btn-size">
{cellValue}</Badge></h5>;
}
else if(cellValue === 'STANDBY'){
return <h5><Badge pill variant="secondary" className="btn-size">
{cellValue}</Badge></h5>;
}
}
const editableColumns = [
{
title: "#",
field: "index",
width: 80,
dir:"asc",
// headerFilter: "input"
},
{
title: "Server Name",
field: "serverName",
hozAlign: "left",
dir:"asc",
},
{
title: "Server Status",
field: "serverStatus",
// width: 100,
hozAlign: 'left',
//formatter: MultiValueFormatter,
formatter: reactFormatter(<SimpleBage />),
},
{
title: "Server Group",
field: "serverGroup",
hozAlign: "left",
},
]
let data = [...jsondata];
const serverListArray =localStorage.getItem("configuration");
class ApplicationServer extends Component {
constructor(props) {
super(props);
this.state = {
data: data,
rowSelection:"",
stopBtnVisible:false,
startBtnVisble:true,
selectedServerName: "",
selectedServerGroup:"",
selectedServerStatus:"",
selectedServerStatusChange:this.state,
positionIdx: 2,
dimModeIdx: "transparent",
isVisible: false,
fluid: true,
customAnimation: true,
slow: true,
size: 0.30,
isServerStarted:this.state,
serverName:null,
rowIndex:null,
};
this.handleVisibleChange = this.handleVisibleChange.bind(this);
this.handleChange = this.handleChange.bind(this);
this.onClose= this.onClose.bind(this);
}
ref = null;
onClose = isVisible =>{
this.setState({ isVisible: false });
}
clearData = () => {
this.setState({ data: [] });
};
handleChange = (handler) =>{
// console.log("update handler data", serverGroup)
// const updatedServerGroup = event.target.value;
// console.log("handle form submit in table", this.state.selectedServerGroup, this.props.serverGroup);
console.log("handle form submit in table", handler);
this.setState({
...handler
//selectedServerGroup:handler.target.serverGroup
})
//console.log("handle form submit in table", this.state);
console.log("handle form submit in table", handler);
}
render(){
const options = {
height: 215,
movableRows: true,
history: true,
movableColumns: true,
resizableRows: true ,
reactiveData:true,
};
const duration = this.state.slow ? 1000 : 100;
const dur = duration / 1000;
const transitions = ['left', 'top', 'width', 'height']
.map(p => `${p} ${dur}s cubic-bezier(0, 1.5, 0.5, 1)`)
.join(',');
console.log("Render data:", serverListArray);
if(Array.isArray(serverListArray) && serverListArray.length>0){
data=[...serverListArray];
//jsondata= serverListArray;
}
return(
<div style={[styles.root]}>
<div style={{
position: 'relative',
height: 'calc(100vh - 50px)',
}}>
<Row className="table-control-bar">
<Col sm={8}><h5>Server Controls</h5></Col>
<Col sm={4} className="text-right">
<Button variant={this.state.failoverButtonVariant}
className="mr-2"
id="serverFailover"
onClick={this.handleServerFailover}
selectedserverName={this.selectedserverName}
disabled={this.state.failoverButtonDisabled}>Failover</Button>
<Button variant={this.state.editButtonVariant}
className="mr-2"
id="serverEdit"
selectedServerName={this.selectedServerName}
disabled={this.state.editButtonDisabled}
onClick={this.handleVisibleChange}>Edit</Button>
{this.state.stopBtnVisible === false &&
(
<Button
onClick={this.handleServerStart}
className="mr-2"
id="serverStart"
selectedserverName={this.selectedserverName}
visible={this.state.startBtnVisible}
variant={this.state.startButtonVariant}
disabled={this.state.startButtonDisabled}>Start
</Button>
)}
{this.state.startBtnVisible === false &&
(<Button onClick={this.handleServerStop}
className="mr-2"
id="serverStop"
selectedserverName={this.selectedserverName}
variant="primary">Stop</Button>)}
<Button variant={this.state.restartButtonVariant}
id="serverRestart"
onClick={this.handleServerRestart}
selectedserverName={this.selectedserverName}
disabled={this.state.restartButtonDisabled}>Restart</Button>
</Col>
</Row>
<div>
<React15Tabulator
columns={editableColumns}
data={data}
selectable={1}
rowClick={this.rowClick}
options={options}
data-custom-attr="test-custom-attribute"
className={"custom-css-class" + this.state.rowSelection}
tooltips={true}
layout={"fitData"}
/>
</div>
</div>
<div>
<Dock position={positions[this.state.positionIdx]}
size={this.state.size}
dimMode={dimModes[this.state.dimModeIdx]}
isVisible={this.state.isVisible}
onVisibleChange={this.handleVisibleChange}
fluid={this.state.fluid}
dimStyle={{ background: 'rgba(0, 0, 100, 0.2)'}, {pointerEvents:'all !important'}}
dockStyle={this.state.customAnimation ? { transition: transitions } : null, {top:'6%'} }
// ,{top:'13%'}
dockHiddenStyle={this.state.customAnimation ? {
transition: [transitions, `opacity 0.01s linear ${dur}s`].join(',')
} : null}
duration={duration}>
{({ position, isResizing }) =>
<div style={[styles.dockContent]} className="modal-container">
<h4>Edit Server Group</h4>
<Divider />
<EditServer
handleInputChange={this.handleChange}
// handleChange = {e => console.log(e)}
serverName={this.state.selectedServerName}
serverGroup= {this.state.selectedServerGroup}
onClose={this.onClose} />
<span onClick={() => this.setState({ isVisible: false })}
style={styles.remove} title="close">✖</span>
</div>
}
</Dock>
</div>
</div>
)
}
handleSizeChange = size => {
this.setState({ size });
}
}
export default ApplicationServer = Radium(ApplicationServer);
CHILD Component is functional component-
import {func, string} from 'prop-types';
import {makeStyles } from '#material-ui/core';
import {Row, Col, Button, Form} from 'react-bootstrap';
import toast from '../../../ui-components/Toaster';
import Input from '../../../ui-components/Input';
const useStyles = makeStyles((theme) => ({
root: {
'& > *': {
margin: theme.spacing(2),
},
},
formControl: {
margin: theme.spacing(1),
minWidth: 120,
maxWidth: 300,
},
chips: {
display: 'flex',
flexWrap: 'wrap',
},
chip: {
margin: 2,
},
noLabel: {
marginTop: theme.spacing(3),
},
}));
function getStyles(name, personName, theme) {
return {
fontWeight:
personName.indexOf(name) === -1
? theme.typography.fontWeightRegular
: theme.typography.fontWeightMedium,
};
}
export default function EditServer(props) {
const {onClose} = props;
let serverGroup = props.serverGroup;
const initialFormState = {
id: null,
serverName: props.serverName,
serverGroup: props.serverGroup,
saveDisabled: true,
cancelDisabled:true,
showDockModal:false,
edited:false,
}
// console.log("inside child", initialFormState);
const [handler, setHandler] = useState();
//const ref = useRef(null);
const handleInputChange = (event) => {
//event.preventDefault();
console.log("edit server props input change", handler);
let { name, value } = event.target;
//handler.serverGroup = event.target.value;
setHandler({...handler, [name]: value, edited:true});
console.log("inside edit form change:", handler, value, name);
}
const handleFormSubmit = (event) => {
//console.log('inside handleFormSubmit', event, props);
event.preventDefault();
onClose();
if (handler.edited){
//let newServerGroup= handler.serverGroup;
//console.log("form submit", handler);
setHandler({
...handler,
edited:false,
});
console.log("inside edit form change:", handler, event)
// props.serverGroup=newServerGroup;
// return handleInputChange(handler.serverGroup.value);
return toast.success(initialFormState.serverGroup + " Server Group Changed to SIMULATION !");
}
}
return (
<React.Fragment>
<Form className="scrollY"
onSubmit={handleFormSubmit}
>
<Row>
<Col sm={4} className="text-align-right">
<label htmlFor="serverName">Server Name<span className="red">*</span></label>
</Col>
<Col sm={8}>
<Input
type="text"
required
id="severName"
name="severName"
// label="Handler Name"
fullWidth
autoComplete="given-name"
value={initialFormState.serverName}
onChange={handleInputChange}
disabled="true"
/>
</Col>
</Row>
<Row>
<Col sm={4} className="text-align-right">
<label htmlFor="serverGroup" required>Server Group<span className="red">*</span></label>
</Col>
<Col sm={8}>
<Input
type="string"
required
id="serverGroup"
name="serverGroup"
// label="Handler Speed"
fullWidth
autoComplete="family-name"
defaultValue={initialFormState.serverGroup}
onChange={handleInputChange}
/>
</Col>
</Row>
<Row>
<Col sm={4}>
{/* <Button variant="secondary" disabled className="btn-custom" onClick={handleClose}>Cancel</Button>*/}
</Col>
<Col sm={8}>
<Button type="submit"
variant="primary"
className="btn-custom"
>
Submit
</Button>
</Col>
</Row>
</Form>
</React.Fragment>
);
}
EditServer.propTypes = {
onSuccess: func,
};
I'm using react tabulator.
Appreciate the help. Thank you.

ReactJS TypeError: this.props. is not a function

I'm building an application, where there is a form presented with different steps. In all the steps but one, I manage to provide the necessary functions as props to make some operations such as 'handleNext', 'handleBack' or 'handleChange'.
Nevertheless, in the last step, represented in the class SuccessForm, when I try to execute the 'handleDownload' function, I get the following error:
TypeError: this.props.handleDownload is not a function
Here it is the SuccessForm.js class:
export class SuccessForm extends Component {
constructor() {
super();
}
download = e => {
e.preventDefault();
this.props.handleDownload();
}
render() {
return (
<React.Fragment>
<Grid container>
<Grid item xs={12} sm={2}>
<DirectionsWalkIcon fontSize="large" style={{
fill: "orange", width: 65,
height: 65
}} />
</Grid>
<Grid>
<Grid item xs={12} sm={6}>
<Typography variant="h5" gutterBottom>
Route created
</Typography>
</Grid>
<Grid item xs={12}>
<Typography variant="subtitle1">
Your new track was succesfully created and saved
</Typography>
</Grid>
</Grid>
<Tooltip title="Download" arrow>
<IconButton
variant="contained"
color="primary"
style={{
marginLeft: 'auto',
// marginRight: '2vh'
}}
onClick={this.download}
>
<GetAppIcon fontSize="large" style={{ fill: "orange" }} />
</IconButton>
</Tooltip>
</Grid>
</React.Fragment>
)
}
}
The entire NewRouteForm.js:
import React, { Component } from 'react'
import { makeStyles, MuiThemeProvider } from '#material-ui/core/styles';
import Paper from '#material-ui/core/Paper';
import Stepper from '#material-ui/core/Stepper';
import Step from '#material-ui/core/Step';
import StepLabel from '#material-ui/core/StepLabel';
import Button from '#material-ui/core/Button';
import Typography from '#material-ui/core/Typography';
import DataForm from '../stepper/dataform/DataForm';
import ReviewForm from '../stepper/reviewform/ReviewForm';
import MapForm from '../stepper/mapform/MapForm';
import NavBar from '../../graphic interface/NavBar';
import DirectionsWalkIcon from '#material-ui/icons/DirectionsWalk';
import Avatar from '#material-ui/core/Avatar';
import CheckCircleOutlineOutlinedIcon from '#material- ui/icons/CheckCircleOutlineOutlined';
import FilterHdrIcon from '#material-ui/icons/FilterHdr';
import Grid from '#material-ui/core/Grid';
import SuccessForm from '../stepper/success/SuccessForm';
import { withStyles } from '#material-ui/styles';
export class NewRouteForm extends Component {
state = {
activeStep: 0,
name: '',
description: '',
date: new Date(),
photos: [],
videos: [],
points: []
};
handleNext = () => {
const { activeStep } = this.state;
this.setState({ activeStep: activeStep + 1 });
};
handleBack = () => {
const { activeStep } = this.state;
this.setState({ activeStep: activeStep - 1 });
};
handleChange = input => e => {
this.setState({ [input]: e.target.value });
}
handleDateChange = date => {
this.setState({ date: date });
}
handleMediaChange = (selectorFiles: FileList, code) => { // this is not an error, is TypeScript
switch (code) {
case 0: // photos
this.setState({ photos: selectorFiles });
break;
case 1: // videos
this.setState({ videos: selectorFiles });
break;
default:
alert('Invalid media code!!');
console.log(code)
break;
}
}
handleMapPoints = points => {
this.setState({ points: points })
}
// ###########################
// Download and Upload methods
// ###########################
handleDownload = () => {
// download route
console.log("DOWNLOAD")
alert("DOWNLOAD");
}
upload = () => {
// upload route
}
render() {
const { activeStep } = this.state;
const { name, description, date, photos, videos, points } = this.state;
const values = { activeStep, name, description, date, photos, videos, points };
const { classes } = this.props;
return (
<MuiThemeProvider>
<React.Fragment>
<NavBar />
<main className={classes.layout}>
<Paper className={classes.paper}>
<Avatar className={classes.avatar}>
<FilterHdrIcon fontSize="large" />
</Avatar>
<Typography component="h1" variant="h4" align="center">
Create your own route
</Typography>
<Stepper activeStep={activeStep} className={classes.stepper}>
{steps.map((label) => (
<Step key={label}>
<StepLabel>{label}</StepLabel>
</Step>
))}
</Stepper>
<React.Fragment>
{activeStep === steps.length ? (
<SuccessForm />
) : (
<React.Fragment>
{getStepContent(activeStep,
values,
this.handleNext,
this.handleBack,
this.handleChange,
this.handleDateChange,
this.handleMediaChange,
this.handleMapPoints,
this.handleDownload
)}
</React.Fragment>
)}
</React.Fragment>
</Paper>
</main>
</React.Fragment>
</MuiThemeProvider>
)
}
}
const steps = ['Basic data', 'Map', 'Review your route'];
function getStepContent(step,
values,
handleNext,
handleBack,
handleChange,
handleDateChange,
handleMediaChange,
handleMapPoints,
handleDownload) {
switch (step) {
case 0:
return <DataForm
handleNext={handleNext}
handleChange={handleChange}
handleDateChange={handleDateChange}
handleMediaChange={handleMediaChange}
values={values}
/>;
case 1:
return <MapForm
handleNext={handleNext}
handleBack={handleBack}
handleMapPoints={handleMapPoints}
values={values}
/>;
case 2:
return <ReviewForm
handleNext={handleNext}
handleBack={handleBack}
values={values}
/>;
case 3:
return <SuccessForm
handleDownload={handleDownload}
/>;
default:
throw new Error('Unknown step');
}
}
const useStyles = theme => ({
layout: {
width: 'auto',
marginLeft: theme.spacing(2),
marginRight: theme.spacing(2),
[theme.breakpoints.up(600 + theme.spacing(2) * 2)]: {
width: 600,
marginLeft: 'auto',
marginRight: 'auto',
},
},
paper: {
marginTop: theme.spacing(3),
marginBottom: theme.spacing(3),
padding: theme.spacing(2),
[theme.breakpoints.up(600 + theme.spacing(3) * 2)]: {
marginTop: theme.spacing(6),
marginBottom: theme.spacing(6),
padding: theme.spacing(3),
},
},
stepper: {
padding: theme.spacing(3, 0, 5),
},
buttons: {
display: 'flex',
justifyContent: 'flex-end',
},
button: {
marginTop: theme.spacing(3),
marginLeft: theme.spacing(1),
},
avatar: {
marginLeft: 'auto',
marginRight: 'auto',
backgroundColor: theme.palette.warning.main,
},
icon: {
width: 65,
height: 65,
},
grid: {
marginLeft: theme.spacing(2),
}
});
export default withStyles(useStyles)(NewRouteForm);
Try calling super(props) in the constructor:
constructor(props) {
super(props);
}
and passing function with this instance (this.handleDownload) as it is a class property:
<SuccessForm handleDownload={this.handleDownload} />
Update:
You have a bug on the last step when you not passing a property:
activeStep === steps.length ? <SuccessForm handleDownload={this.handleDownload}/>
Assuming that you have a class in your parent Component, what you're missing is the this keyword in the function reference...
case 3:
return <SuccessForm
handleDownload={this.handleDownload}
/>;

react-form-validator not registering children components?

I am using 'react-form-validator-core' package and trying to create a custom form validator that implements 'mui-downshift', a Material UI implementation of PayPal's downshift. This question is mostly about 'react-form-validator-core' package itself. The problem is that the form itself does not register the validator component I've created. Here is my full code of the custom component and the form itself. I've exhausted my debugging skills, but what I noticed is that there's something wrong with the this.context in the form...
Validator component:
import React from 'react';
import PropTypes from 'prop-types';
import MuiDownshift from 'mui-downshift';
import { ValidatorComponent } from 'react-form-validator-core';
class AutocompleteValidator extends ValidatorComponent {
constructor(props) {
debugger;
super(props);
this.originalItems = props.items.map(({key, name}) => ({ text: name, value: key }));
this.handleStateChange = this.handleStateChange.bind(this);
this.errorText = this.errorText.bind(this);
}
componentWillMount() {
if (!this.filteredItems) {
this.setState({filteredItems: this.originalItems});
}
if (!!this.props.value) {
const selectedItem = this.originalItems.filter(
item => item.value.toLowerCase().includes(this.props.value.toLowerCase())
)[0];
this.setState({ selectedItem })
} else {
this.setState({ selectedItem: null})
}
}
componentWillReceiveProps(nextProps) {
// If no filteredItems in sate, get the whole list:
if (!nextProps.value) {
this.setState({ isValid: false })
}
}
handleStateChange(changes) {
// If searching
if (changes.hasOwnProperty('inputValue')) {
const filteredItems = this.originalItems.filter(
item => item.text.toLowerCase().includes(changes.inputValue.toLowerCase())
);
this.setState({ filteredItems })
}
// If something is selected
if (changes.hasOwnProperty('selectedItem')) {
!!changes.selectedItem ? this.setState({isValid: true}) : this.setState({isValid: false})
// If we get undefined, change to '' as a fallback to default state
changes.selectedItem = changes.selectedItem ? changes.selectedItem : '';
this.props.onStateChange(changes);
}
}
errorText() {
const { isValid } = this.state;
if (isValid) {
return null;
}
return (
<div style={{ color: 'red' }}>
{this.getErrorMessage()}
</div>
);
}
render() {
return (
<div>
<MuiDownshift
{...this.props}
items={this.state.filteredItems}
onStateChange={this.handleStateChange}
ref={(r) => { this.input = r; }}
defaultSelectedItem={this.state.selectedItem}
/>
{this.errorText()}
</div>
);
}
}
AutocompleteValidator.childContextTypes = {
form: PropTypes.object
};
export default AutocompleteValidator;
A component where it's used:
render() {
return (
<ValidatorForm
ref='form'
onSubmit={() => {
this.context.router.history.push(this.props.config.urls['step5']);
}}
onError={errors => console.log(errors)}
>
<Row>
<Col md={12}>
<AutocompleteValidator
validators={['required']}
errorMessages={['Cette information doit être renseignée']}
isRequired={true}
name='bankId'
items={this.props.config.list.bank}
onStateChange={(changes) => {
this.props.loansUpdate('bankId', changes.selectedItem.value);
}}
value={!!this.props.loans.bankId ? this.props.loans.bankId : false}
/>
</Col>
</Row>
<Row>
<Col md={12} style={{ marginTop: '15px' }}>
<Checkbox
label={<Translate value='step4.insuranceProvidedByBank' />}
labelStyle={{ 'top': '0px' }}
name='insuranceProvidedByBank'
value={this.props.loans.insuranceProvidedByBank}
checked={this.props.loans.insuranceProvidedByBank}
onCheck={(event, value) => {
this.props.loansUpdate('insuranceProvidedByBank', value);
}}
/>
</Col>
</Row>
<Row>
<Col sm={6} md={5}>
<Button
fullWidth
style={{ marginTop: '50px', marginBottom: '20px' }}
type='submit'
icon={<i className='fa fa-angle-right' style={{ marginLeft: '10px', display: 'inline-block' }} />}
><Translate value='iContinue' /></Button>
</Col>
</Row>
</ValidatorForm >
)
};
};
you get this problem because you override default componentWillMount and componentWillReceiveProps methods from ValidatorComponent. So, to solve this case you should do something like this
componentWillMount() {
// should call parent method before
super.componentWillMount();
// your code
}

Unexpected token - react/js

I'm trying to run a project, but the same is displaying an error in the console related to a function I have, the error is as follows:
"63:25 error Parsing error: Unexpected token, expected (function toggleDrawer = (open) => () => {^ state = {"
My project is this:
import React from 'react';
import PropTypes from 'prop-types';
import { Link } from 'react-router-dom';
import { withStyles } from 'material-ui/styles';
import AppBar from 'material-ui/AppBar';
import Drawer from 'material-ui/Drawer';
import Button from 'material-ui/Button';
import IconButton from 'material-ui/IconButton';
import Toolbar from 'material-ui/Toolbar';
import MenuIcon from 'material-ui-icons/Menu';
import TextField from 'material-ui/TextField';
import Paper from 'material-ui/Paper';
import Grid from 'material-ui/Grid';
import '../assets/scss/main.scss';
import img from '../assets/images/react.png';
const styles = theme => ({
root: {
width: '100%',
},
flex: {
flex: 1,
},
menuButton: {
marginLeft: -12,
marginRight: 20,
},
inputProps: {
step: 300,
},
button: {
margin: theme.spacing.unit,
},
input: {
display: 'none',
},
paper: {
padding: 50,
textAlign: 'center',
border: '5px solid black',
width: '100%',
},
paper1: {
backgroundColor: 'red',
marginTop: '13%',
},
img: {
width: '45%',
},
appbar: {
marginLeft: '-20.20%',
marginTop: '-20%',
width: '139.99%',
},
});
function ButtonAppBar(props) {
const { classes } = props;
const state = {
inputs: {},
};
function toggleDrawer = (open) => () => {
state={
open:false,
};
this.setState({
open,
});
};
const updateInputValue = (evt) => {
state.inputs[evt.target.name] = evt.target.value;
console.log(state.inputs);
};
const handleSubmit = (event) => {
// console.log('handleSubmit', username, password);
if (!event.target.checkValidity()) {
console.log({ displayErrors: true });
}
event.stopPropagation();
event.preventDefault();
return 0;
};
return (
<div className={styles.root}>
<Grid container spacing={8} alignItems="center" justify="center">
<Paper className={classes.paper}>
<AppBar position="static" className={classes.appbar}>
<Toolbar>
<IconButton onClick={this.toggleDrawer(true)} className={classes.menuButton} color="contrast" aria-label="Menu">
<Drawer open={this.state.open} onClose={this.toggleDrawer('open', false)}>
onClick={this.toggleDrawer('open', false)}
</Drawer>
<MenuIcon />
</IconButton>
</Toolbar>
</AppBar>
<img src={img} alt="React" className={classes.img} /><br />
<form onSubmit={handleSubmit} noValidate>
<TextField id="email" type="email" label="Usuário" className={classes.user} value={state.inputs.username} onChange={evt => updateInputValue(evt)} /><br />
<TextField id="password" type="password" label="Senha" className={classes.senha} value={state.inputs.password} onChange={evt => updateInputValue(evt)} />
<AppBar position="static" className={classes.paper1}>
<Link to="/Orders">
<Button type="submit" color="contrast">Login</Button>
</Link>
</AppBar>
</form>
</Paper>
</Grid>
</div>
);
}
ButtonAppBar.propTypes = {
classes: PropTypes.object.isRequired,
};
export default withStyles(styles)(ButtonAppBar);
I wonder why this error is happening (I am a beginner in react).
It is a syntax error.
Replace function toggleDrawer = to
const toggleDrawer =

Categories