newbreedofgeek / react-stepzilla

A React multi-step/wizard component for sequential data collection
https://newbreedofgeek.github.io/react-stepzilla/
ISC License
618 stars 176 forks source link

not start isValidated method (react refs new style) #34

Open romanlex opened 7 years ago

romanlex commented 7 years ago

I cannot start isValidated() method in my step I found what stepMoveAllowed(skipValidationExecution = false) method in StepZIlla cannot properly check this because this.refs is empty

else if (Object.keys(this.refs).length == 0 || typeof this.refs.activeComponent.isValidated == 'undefined') {
                console.log(this.refs); // return EMPTY OBJECT
                // if its a form component, it should have implemeted a public isValidated class (also pure componenets wont even have refs - i.e. a empty object). If not then continue
                proceed = true;
            }
my libraries
"react": "^15.3.2",
    "react-addons-css-transition-group": "^15.5.2",
    "react-bootstrap": "^0.30.10",
    "react-dom": "^15.5.4",
    "react-dropzone": "^3.13.0",
    "react-hot-loader": "^3.0.0-beta.6",
    "react-overlays": "^0.6.12",
    "react-redux": "^5.0.4",
    "react-router": "3.0.5",
    "react-router-bootstrap": "^0.23.2",
    "react-router-dom": "^4.1.1",
    "react-router-redux": "^4.0.8",
romanlex commented 7 years ago

I change to stepMoveAllowed() method....but cant check with HOC validation

stepMoveAllowed(skipValidationExecution = false) {
        let proceed = false;
        if (this.props.dontValidate) {
            proceed = true;
        }
        else {
            if (skipValidationExecution) {
                // we are moving backwards in steps, in this case dont validate as it means the user is not commiting to "save"
                proceed = true;
            }
            else if (this.props.hocValidationAppliedTo.length > 0 && this.props.hocValidationAppliedTo.indexOf(this.state.compState) > -1) {
                // the user is using a higer order component (HOC) for validation (e.g react-validation-mixin), this wraps the StepZilla steps as a HOC, so use hocValidationAppliedTo to determine if this step needs the aync validation as per react-validation-mixin interface
                proceed = this.activeComponent.isValidated();
            }
            else if (typeof this.props.steps[this.state.compState].component.type.prototype.isValidated === 'undefined') {
                // if its a form component, it should have implemeted a public isValidated class (also pure componenets wont even have refs - i.e. a empty object). If not then continue
                proceed = true;
            }
            else {
                // user is moving forward in steps, invoke validation as its available
                proceed = this.activeComponent.isValidated();
            }
        }

        return proceed;
    }

and in render method change refs:

...
        const componentPointer = this.props.steps[this.state.compState].component;

        // can only update refs if its a regular React component (not a pure component), so lets check that
        if (componentPointer instanceof Component || // unit test deteceted that instanceof Component can be in either of these locations so test both (not sure why this is the case)
            (componentPointer.type && componentPointer.type.prototype instanceof Component)) {
            cloneExtensions.ref = (ref) => { this.activeComponent = ref };
            cloneExtensions.key = window.location.pathname;
        }

        compToRender = React.cloneElement(componentPointer, cloneExtensions);
...
newbreedofgeek commented 7 years ago

@romanlex Is your Step component a pure component?

Can you paste your Step code or post a complete example.

jnordling commented 7 years ago

I am having this issue also. Here is a full component. @romanlex change seems to work for me.

When i debug this.refs.activeComponent.refs.component seems this is undefined but and this.refs.activeComponent.isValidated() works for me.

import React from "react";
import {config} from 'components/create/config';
import {createActions} from 'components/create/actions/createActions';
import {createStore} from 'components/create/stores/createStore';
export default class CreateType extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
        options: config.createType.options,
        selected_type_id:props.getStore().create_type
    };
    this.isValidated = this.isValidated.bind(this);
  }

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

  componentDidMount(){
    console.log("componentDidMount")  
  }

  setActiveType(event){
    createActions.updateCreateType(event.target.id);
    this.setState({selected_type_id: event.target.id});
  }

  isValidated() {
    // Do some checking
    return true
  }

  render() {
    return (
        <section className="create_section">  
          {
            this.state.options.map(option =>{
              return ( 
                <div className="create_type_container" id={option.id} key={option.id} onClick={this.setActiveType.bind(this)}>
                  <h4 className="create_label">{option.label}</h4>
                </div>
              )
            })
          }
        </section>
    );
  }
}
newbreedofgeek commented 7 years ago

@jnordling @romanlex let me look into this further. I noticed that in @romanlex's package.json, that your "react": "^15.3.2" and "react-dom": "^15.5.4" don't match... I could be wrong but I believe it's best practice that they match in version.

I do suspect this has something to do with your higher react-dom version, but let me investigate.

j3t11ro commented 7 years ago

I've run into the same issue and @romanlex fix has worked for me so far. Will stay tuned for a more official fix/update.

Thanks!

rubystar commented 7 years ago

@newbreedofgeek is there a chance for this to be fixed soon, I'll definitely need this. I mean this feature is one of the reasons i wanted to use this library. Thanks

mhidalgop commented 7 years ago

I also need this feature, in my opinion is the point that makes better this library compared to others. On the other hand, with @romanlex fix, isValidated is firing, the problem is that inside isValidated method this.props is undefined, so I can't fire getStore()/updateStore(). The difference between @romanlex fix and mine is that I have a child component like this: {name: 'Primary Application', component: <GenericStep explanation = {this.explanation1} ><PrimaryApplication getStore={() => (this.getStore())} updateStore={(u) => {this.updateStore(u)}}/></GenericStep>}

So I'm calling isValidate like this proceed = this.refs.activeComponent.props.children.type.prototype.isValidated();

Could be this the reason of my issue?

shivan4030 commented 7 years ago

i have run into the same issue, please let me know if any of you found an a way to solve it !!

SebastienTolron commented 4 years ago

Hey guys ,

Having the same issue.

MainComponent :

        <div className='step-progress'>
          <StepZilla
            steps={this.getSteps()}
            nextTextOnFinalActionStep="Save"
            hocValidationAppliedTo={[5]}
            prevBtnOnLastStep={false}
          />
        </div>

My step 5

import React, {useState, Component, Fragment} from 'react';
import {FormattedMessage} from 'react-intl';
import messages from './messages';
import Card from 'components/Card/Loadable'
import {Grid, Button, TextField} from '@material-ui/core'
import SweetAlert from 'sweetalert-react';
import {toast} from 'react-toastify'
import 'sweetalert/dist/sweetalert.css';
import './style.scss'
import {Helmet} from "react-helmet";
import Promise from 'promise';

class ClusterCreateStepReview extends Component {
  constructor(props) {
    super(props);
    this.isValidated = this.isValidated.bind(this);
  }

  isValidated() {
    // Do some checking
    return true
  }

  render() {
    return (
      <Fragment>
        <div className="stepper-content">
          <Grid item xs={12}>
            <Card title="Summary">
              Cluster name
            </Card>
          </Grid>
        </div>
      </Fragment>
    )
  }
}

export default ClusterCreateStepReview;

And having this issue :

react-dom.development.js?61bb:289 Uncaught TypeError: Cannot read property 'refs' of undefined
    at StepZilla.stepMoveAllowed (main.js?90db:304)
    at StepZilla.abstractStepMoveAllowedToPromise (main.js?90db:325)
    at StepZilla.next (main.js?90db:248)
    at onClick (main.js?90db:407)
    at HTMLUnknownElement.callCallback (react-dom.development.js?61bb:149)
    at Object.invokeGuardedCallbackDev (react-dom.development.js?61bb:199)
    at invokeGuardedCallback (react-dom.development.js?61bb:256)
    at invokeGuardedCallbackAndCatchFirstError (react-dom.development.js?61bb:270)
    at executeDispatch (react-dom.development.js?61bb:561)
    at executeDispatchesInOrder (react-dom.development.js?61bb:583)

Issue seems to be here

          proceed = this.refs.activeComponent.refs.component.isValidated();

image

My knowledge in React is very limited , so might be something I'm doing wrong ?

terrykyee commented 4 years ago

This is a pretty important issue for myself as well. Our group specifically chose this component for its validation capability, and I'm running into this same issue.

man0a commented 4 years ago

Think there is a calculation error somewhere. I was trying to trigger isValidate() for my first step but it always failed on the line mentioned above proceed = this.refs.activeComponent.refs.component.isValidated();

I changed hocValidationAppliedTo={[0]} to hocValidationAppliedTo={[-1]} and it started working 🤷