Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TypeError: Cannot read property 'IsValidated' of undefined #80

Open
dk4210 opened this issue Jan 25, 2018 · 10 comments
Open

TypeError: Cannot read property 'IsValidated' of undefined #80

dk4210 opened this issue Jan 25, 2018 · 10 comments

Comments

@dk4210
Copy link

dk4210 commented Jan 25, 2018

Hello I see that other people were having this issue but I didn't see a clear answer.

the steps work great, its the validation I'm having an issue with. Please advise.

Here's the complete error

main.js?e1d2:318 Uncaught TypeError: Cannot read property 'isValidated' of undefined
    at StepZilla.stepMoveAllowed (main.js?e1d2:318)
    at StepZilla.abstractStepMoveAllowedToPromise (main.js?e1d2:341)
    at StepZilla.next (main.js?e1d2:255)
    at onClick (main.js?e1d2:444)
    at HTMLUnknownElement.callCallback (react-dom.development.js?cada:540)
    at Object.invokeGuardedCallbackDev (react-dom.development.js?cada:579)
    at Object.invokeGuardedCallback (react-dom.development.js?cada:436)
    at Object.invokeGuardedCallbackAndCatchFirstError (react-dom.development.js?cada:450)
    at executeDispatch (react-dom.development.js?cada:834)
    at executeDispatchesInOrder (react-dom.development.js?cada:853)

I have a component (Step1) and here is the code

'use strict';

import React, { PropTypes, Component } from 'react';
import { Row, Col, Button,  ButtonDropdown, DropdownToggle, DropdownMenu, DropdownItem, Card, CardHeader, CardFooter, CardBody, Form, FormGroup, FormText, Label, Input,
InputGroup, InputGroupAddon, InputGroupButton} from 'reactstrap';

 
class Step1 extends Component {
  constructor(props) {
    super(props)

    // sets state of package name
    this.state = {
      email: props.getStore().packagename,
      gender: props.getStore().gender
    };

    // This flag enables onBlur validation as user fills out forms.
    this._validateOnDemand = true;

    // Bind 
    this.validationCheck = this.validationCheck.bind(this);
    this.isValidated = this.isValidated.bind(this);
    }

    componentDidMount() {
    //  console.log("componentDidMount")  
    }
  
    componentWillMount() {
    //  console.log("componentWillMounts")
    }

    isValidated() {
      const userInput = this._grabUserInput(); // grab user entered vals
      const validateNewInput = this._validateData(userInput); // run the new input against the validator
      let isDataValid = false;
  
      // if full validation passes then save to store and pass as valid
      if (Object.keys(validateNewInput).every((k) => { return validateNewInput[k] === true })) {
          if (this.props.getStore().packagename != userInput.packagename) { // only update store of something changed
            this.props.updateStore({
              ...userInput,
              savedToCloud: false // use this to notify step4 that some changes took place and prompt the user to save again
            });  // Update store here (this is just an example, in reality you will do it via redux or flux)
          }

         
  
          isDataValid = true;
      }
      else {
          // if anything fails then update the UI validation state but NOT the UI Data State
          this.setState(Object.assign(userInput, validateNewInput, this._validationErrors(validateNewInput)));
      }
  
      return isDataValid;
    }

    validationCheck() {
      if (!this._validateOnDemand)
        return;
  
      const userInput = this._grabUserInput(); // grab user entered vals
      const validateNewInput = this._validateData(userInput); // run the new input against the validator
  
      this.setState(Object.assign(userInput, validateNewInput, this._validationErrors(validateNewInput)));
    }

    _validateData(data) {
      return  {
        packagenameVal: (data.packagename != 0) // required: anything besides N/A
        }
    }



    _validationErrors(val) {
      const errMsgs = {
        packagenameValMsg: val.packagenameVal ? '' : 'A Package Name required'
        
      }
      return errMsgs;
    }

    _grabUserInput() {
      return {
        packagename: this.refs.packagename.value
        
      };
    }



render() {

  // Explicit class assigning based on validation 

   // explicit class assigning based on validation
   let notValidClasses = {};
   
       if (typeof this.state.packagenameVal == 'undefined' || this.state.packagenameVal) {
         notValidClasses.packagenameCls = 'no-error col-md-8';
       }
       else {
          notValidClasses.packagenameCls = 'has-error col-md-8';
          notValidClasses.packagenameValGrpCls = 'val-err-tooltip';
       }
   
      
  

return (
    <div className="step step1">
      <div className="row">
      
        <form id="Form" className="form-horizontal">
            <div id="stepscontainer" className="form-group">
            <label className="col-md-12 control-label">
              <h2>Please provide a unique name for the package</h2>
            </label>
            <div className="row content">
              <div className="col-md-12">
                  Give a short name that can identify the package with, using underscore and no spaces.
                  <br /><br />
                     <FormGroup row>
                     <Col xs="12" md="9">
                     <div className={notValidClasses.packagnameCls}>
                     <Input ref="packagename" 
                     autoComplete = "off"
                     placeholder="Enter package name"
                     type="packagename" 
                     className="form-control"
                     required
                     defaultValue={this.state.packagename}
                     id="packagename" 
                     onBlur={this.validationCheck}
                     size="145" />
                    <div className={notValidClasses.packagenameValGrpCls}>{this.state.packagenameValMsg}</div>
                    </div>
                    </Col>
                  </FormGroup>
              
              </div>
              <div className="col-md-12 eg-jump-lnk">
               
              </div>
            </div>
          </div>
          
        </form>
      </div>
      </div>
    )
  }
}

export default Step1;

Here's my code for my dashboard (Kinda like your example.js)

import React, { Component } from 'react';
import {connect} from 'react-redux';
import {Bar, Line} from 'react-chartjs-2';
import { Badge, Row, Col, Progress, Dropdown, DropdownToggle, DropdownMenu, DropdownItem, Card, CardHeader, CardBody, CardFooter, CardTitle, Container, Button, ButtonToolbar,
  ButtonGroup, ButtonDropdown, Label, Input, Table, Form, FormGroup, FormText, InputGroup, InputGroupAddon,  InputGroupButton, Modal, ModalHeader, ModalBody, ModalFooter
} from 'reactstrap';
import SelectPackagePanel from '../Components/SelectPackagePanel/SelectPackagepanel.jsx';
import StepZilla from 'react-stepZilla';
import Step1 from '../Components/Step1/step1.jsx';
import Step2 from '../Components/Step2/step2.jsx';
import Step3 from '../Components/Step3/step3.jsx';
import Step4 from '../Components/Step4/step4.jsx';
import Step5 from '../Components/Step5/step5.jsx';



class Dashboard extends Component {
  constructor(props) {
    super(props);

    

   


    this.state = {};

    this.packageStore = {
      packagename: '',
      savedToPersist: false
    };
   
    this.togglePrimary = this.togglePrimary.bind(this);

  }

  togglePrimary() {
    this.setState({
      primary: !this.state.primary
    });

  }

  componentDidMount() {}
  
  componentWillUnmount() {}

  getStore() {
    return this.packageStore;
  }

  updateStore(update) {
    this.packageStore = {
      ...this.packageStore,
      ...update,
    }
  }
 

  render() {

    
    
    const steps =
    [
      {name: 'Package Name', component: <Step1 getStore={() => (this.getStore())} updateStore={(u) => {this.updateStore(u)}} />},
      {name: 'Package Type', component: <Step2 getStore={() => (this.getStore())} updateStore={(u) => {this.updateStore(u)}} />},
      {name: 'Step3', component: <Step3 getStore={() => (this.getStore())} updateStore={(u) => {this.updateStore(u)}} />},
      {name: 'Step4', component: <Step4 getStore={() => (this.getStore())} updateStore={(u) => {this.updateStore(u)}} />},
      {name: 'Step5', component: <Step5 getStore={() => (this.getStore())} updateStore={(u) => {this.updateStore(u)}} />},
    ]

    return (
      <div className="animated fadeIn">
       
       
    
       {/* <SelectPackagePanel /> */}
       <div className="homebg">
       <Container>
         
        <Row>
        <Col xs="12" sm="6" md="6" id="homecol1">
            <Card id="homeshadow" className="border-info">
              <CardHeader>
                Welcome to CDS
              </CardHeader>
              <CardBody>
                <div className="homecontentcontainer">
               <strong> <div className="hometitle">What would you like to do? </div> </strong>
               
                <Col md="12">
                      <FormGroup check>
                        <div className="radio">
                          <Label check htmlFor="radio1">
                            <Input type="radio" id="radio1" name="radios" value="option1"/> Create a new content Package
                          </Label>
                        </div>
                        <div className="radio">
                          <Label check htmlFor="radio2">
                            <Input type="radio" id="radio2" name="radios" value="option2"/> Work with an existing package
                          </Label>
                        </div>
                        <div className="radio">
                          <Label check htmlFor="radio3">
                            <Input type="radio" id="radio3" name="radios" value="option3"/> Take me to Test Workflow
                          </Label>
                        </div>
                   <div className="homesubmit">
                   <Button color="primary" onClick={this.togglePrimary}>Submit</Button>
                   <Modal isOpen={this.state.primary} toggle={this.togglePrimary}
                   className={'modal-primary ' + this.props.className}>
                  <ModalHeader toggle={this.togglePrimary}>Create a package</ModalHeader>
                  <ModalBody>
                  <div className='example'>
                  <div className='step-progress'>
                  <StepZilla
                  steps={steps}
                  preventEnterSubmission={true}
                  nextTextOnFinalActionStep={"Next"}
                  hocValidationAppliedTo={[0]}
                  startAtStep={window.sessionStorage.getItem('step') ? parseFloat(window.sessionStorage.getItem('step')) : 0}
                  onStepChange={(step) => window.sessionStorage.setItem('step', step)}
                   />
                  </div>
                  </div>
                  </ModalBody>
                  
                </Modal>
                        </div>
                       
                      </FormGroup>
                    </Col>
                    </div>
               
                
              </CardBody>
            </Card>
          </Col>
        </Row>
        </Container>
      </div>
      </div>
    )
  }
}

export default Dashboard;
@Adamkzh
Copy link

Adamkzh commented Mar 6, 2018

Got the same problem

@aogaili
Copy link

aogaili commented Mar 28, 2018

Same here..

@Sotrek
Copy link

Sotrek commented Oct 1, 2018

same here..

@IronTony
Copy link

same here...

@tabrindle
Copy link

I believe I have traced the probable cause of these errors.

Turns out that there is code that checks a react component's prototype for an isValidated method.

The problem is that arrow functions () => {} do not have a prototype

if you had a component like this, you would throw Cannot read property 'isValidated' of undefined because prototype doesn't exist here.

const LoadingView = ({ top, title }) => (
  <Loading top={top}>
    <h4>{title}</h4>
  </Loading>
);

Long story short, this was hard to track down because of Babel - Older presets like es2015 (like used in this library, including its tests) will transpile this component like this:

"use strict";

var LoadingView = function LoadingView(_ref) {
  var top = _ref.top,
      title = _ref.title;
  return React.createElement(
    Loading,
    { top: top },
    React.createElement(
      "h4",
      null,
      title
    )
  );
};

Notice the change to a regular function? This function has a prototype, and will not throw.

Now, say you upgrade an existing app using react-stepzilla to Babel 7, and use preset-env for modern browsers. This is now your transpiled component. And boom, no prototype so this method throws.

"use strict";

const LoadingView = (_ref) => {
  let top = _ref.top,
      title = _ref.title;
  return React.createElement(
    Loading,
    { top: top },
    React.createElement(
      "h4",
      null,
      title
    )
  );
};

The easiest workaround here is to use a standard function() {} instead of () => {}

Realistically, this isn't much of a permanent solution. A safer property access on the react components, not assuming a prototype property exists should be enough to fix this bug.

https://github.com/newbreedofgeek/react-stepzilla/blob/master/src/main.js#L33

I would also recommend a different babel preset for your tests, possibly leaving arrow functions intact. They are pretty universally well supported now

@newbreedofgeek
Copy link
Owner

Interesting, thanks for detailed debug in the above comment. Yes, I believe it is caused due to the pure component. I will look at a possible fix as I’m working on the Redux demo as part of #134

I can’t recall if any of the other demo code used pure compenets and the older Babel was allowing it to work??

@newbreedofgeek
Copy link
Owner

Mmmm just realised that isValidated as a Static might do the trick, but not sure if Static is supported in pure components?

@Lilian1331
Copy link

hi i am facing the same issue. Any updates?

astrosalinas added a commit to astrosalinas/react-stepzilla that referenced this issue Jul 16, 2019
@igor-plotnikov
Copy link

igor-plotnikov commented Dec 20, 2019

Is this supposed to be fixed now? I've just tried using the component installing it via npm, and see the same crash.

I'm not using functional components. What could be wrong?

@tarsusi
Copy link

tarsusi commented Jul 26, 2020

@dk4210, today, I had the same problem and after some debugging on the code, I realized that the package(react-stepzilla) cannot find the isValidated property since it cannot find the step component's prototype. This was because my component, that is used in step, was a functional component

const FeedbackSelfThanks = (props) => { return 'Something'; }

I changed the component to class one:

class FeedbackSelfThanks extends React.Component { render() { return 'Something'; } }

Now, the error has gone. Maybe this help you

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

10 participants