Search code examples
javascriptreactjsmaterial-uijsxcreate-react-app

Variable substitution parsing error (unexpected token, expected "...")


I have some code which dynamically adjusts a text field.

This version of the code works ok:

  if (props.responsetxt === null) {
    txtField = (
      <TextField
        autoFocus
        margin="dense"
        id="name"
        label={emailField}
        type="email"
        fullWidth
        onChange={e => emailFieldUpdate(e)}
      />
    );

However I am using material-ui and I want to make use of their error option (https://material-ui.com/demos/text-fields/)

But if I modify my code as follows :

let errorFlag = null;  // add this
    txtField = (
      <TextField
        {errorFlag} // add this
        autoFocus
        margin="dense"
        id="name"
        label={emailField}
        type="email"
        fullWidth
        onChange={e => emailFieldUpdate(e)}
      />
    );

I get an error:

Parsing error: Unexpected token, expected "..."

  Line 45:  Parsing error: Unexpected token, expected "..."

  43 |     txtField = (
  44 |       <TextField
> 45 |         {errorFlag}
     |          ^
  46 |         autoFocus
  47 |         margin="dense"
  48 |         id="name"

I do not understand why label and onChange dynamic parameters can work OK but the {errorFlag} substitution cannot ?

UPDATE

function DownloadForm(props) {
  const intl = props.intl;
  const boxTitle = intl.formatMessage({ id: 'downloadRequest.title' });
  const cancelButton = intl.formatMessage({ id: 'button.cancel' });
  const closeButton = intl.formatMessage({ id: 'button.close' });
  const downloadButton = intl.formatMessage({ id: 'button.download' });
  const emailField = intl.formatMessage({ id: 'downloadRequest.emailField' });
  let boxText = null;
  let waitingAnimation = null;
  let returnArr = {};
  let errorFlag = null;
  const emailFieldUpdate = e => {
    returnArr['email'] = e.target.value;
    if (!EmailValidator(e.target.value)) {
        console.log('setting true !');
        errorFlag=true;
    }
  };
  returnArr['subset'] = props.selectedSubset;
  if (props.showWaitingAnimation) {
    waitingAnimation = <CircularProgress />;
  }
  if (props.responsetxt === null) {
    returnArr['correlID'] = UUIDGenerator();
    returnArr['boxOpened'] = TAI64.now().toHexString();
    boxText = intl.formatMessage({ id: 'downloadRequest.prompt' });
  } else {
    boxText = props.responsetxt;
}
  let txtField, submitButton, closeText;
  if (props.responsetxt === null) {
    txtField = (
      <TextField
        error={errorFlag}
        autoFocus
        margin="dense"
        id="name"
        label={emailField}
        type="email"
        fullWidth
        onChange={e => emailFieldUpdate(e)}
      />
    );
    submitButton = (
      <Button
        color="primary"
        onClick={() =>
          props.submit(returnArr, process.env.REACT_APP_ITS_AWS_SQS_DOWNLOAD)
        }
      >
        {downloadButton}
      </Button>
    );
    closeText = cancelButton;
  } else {
    closeText = closeButton;
  }
  return (
    <div>
   <Dialog open={props.open} aria-labelledby="form-dialog-title">
        <DialogTitle id="form-dialog-title">{boxTitle}</DialogTitle>
        <DialogContent>
          <DialogContentText>{boxText}</DialogContentText>
          {waitingAnimation}
          {txtField}
        </DialogContent>
        <DialogActions>
          <Button color="primary" onClick={props.close}>
            {closeText}
          </Button>
          {submitButton}
        </DialogActions>
      </Dialog>
    </div>
  );
}
export default injectIntl(DownloadForm);

Solution

  • From the doc :

      <TextField
          error
          id="standard-error"
          label="Error"
          defaultValue="Hello World"
          className={classes.textField}
          margin="normal"
      />
    

    The error here is the short syntax of error={true} which is not possible to reproduce dynamically. However, you can do the following :

      <TextField
        error={errorFlag}
        autoFocus
        margin="dense"
        id="name"
        label={emailField}
        type="email"
        fullWidth
        onChange={e => emailFieldUpdate(e)}
      />
    

    And as your error message is telling you, deconstructing a single attribute JSON may also work :

      <TextField
        ...{error : errorFlag}
    

    Renaming it to error will reduce the syntax even further :

      <TextField
        ...{error}
    

    EDIT :

    You are using a stateless React component, which means that it is never going to re-render by itself, and calling emailFieldUpdate won't either. I refactored your component into a stateful one, where errorFlag is now in your state.

    Calling this.setState({ errorFlag: true }) will update your flag and rerender your component, showing you the error. I also made few code readability changes :

    import React, { Component } from 'react'
    export default class DownloadForm extends Component {
        constructor(props) {
            super(props)
    
            this.state = {
                errorFlag: null,
                returnArr: {}
            }
        }
    
        emailFieldUpdate = e => {
            this.setState({ returnArr:{ email: e.target.value }})
            if (!EmailValidator(e.target.value)) {
                console.log('setting true !');
                this.setState({ errorFlag: true })
            }
        };
    
        render() {
            const { selectedSubset, responsetxt, showWaitingAnimation, intl, submit, open, close } = this.props //Decontructs your props
            const { errorFlag, returnArr } = this.state //Deconstructs your state
    
            const [boxTitle, cancelButton, closeButton, downloadButton, emailField] = 
            ['downloadRequest.title', 'button.cancel', 'button.close', 'button.download', 'downloadRequest.emailField'].map(id =>
                intl.formatMessage({ id })
            );
            let boxText = null;
            let waitingAnimation = null;
    
            returnArr['subset'] = selectedSubset;
            if (showWaitingAnimation) {
                waitingAnimation = <CircularProgress />;
            }
            if (!responsetxt) {
                returnArr['correlID'] = UUIDGenerator();
                returnArr['boxOpened'] = TAI64.now().toHexString();
                boxText = intl.formatMessage({ id: 'downloadRequest.prompt' });
            } else {
                boxText = responsetxt;
            }
            return (
                <div>
                    <Dialog open={open} aria-labelledby="form-dialog-title">
                        <DialogTitle id="form-dialog-title">{boxTitle}</DialogTitle>
                        <DialogContent>
                            <DialogContentText>{boxText}</DialogContentText>
                            {waitingAnimation}
                            {!responsetxt && 
                                <TextField
                                    error={errorFlag}
                                    autoFocus
                                    margin="dense"
                                    id="name"
                                    label={emailField}
                                    type="email"
                                    fullWidth
                                    onChange={this.emailFieldUpdate}
                                />
                            }
                        </DialogContent>
                        <DialogActions>
                            <Button color="primary" onClick={close}>
                                {responsetxt ? closeButton : cancelButton}
                            </Button>
                            {!responsetxt && 
                                <Button
                                    color="primary"
                                    onClick={() => {submit(returnArr, process.env.REACT_APP_ITS_AWS_SQS_DOWNLOAD)}}>
                                    {downloadButton}
                                </Button>
                            }
                        </DialogActions>
                    </Dialog>
                </div>
            );
        }
    }
    

    You seem to be using React-intl, look at this documentation to make your messages directly into your JSX : https://github.com/yahoo/react-intl/wiki/Components#formattedmessage

    Also I suggest reading conditional rendering in React and deconstruction in JS