TypeError: Cannot read property 'IsValidated' of undefined
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;
Got the same problem
Same here..
same here..
same here...
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
- https://caniuse.com/#feat=arrow-functions
- https://node.green/#ES2015-functions-arrow-functions
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??
Mmmm just realised that isValidated as a Static might do the trick, but not sure if Static is supported in pure components?
hi i am facing the same issue. Any updates?
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?
@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