Skip to content Skip to sidebar Skip to footer

Enable The Go To Next Step Button, Tried Setting Up State And Created New Onclick Method In The Radio Button

update 2: hi, sorry I forgot to mention about the api call in my question earlier I making an api call in redux way. so in my actions/index.js file I am calling my api in getSpor

Solution 1:

https://codesandbox.io/s/6zrw7r66rr

I have forked your codesandbox, and edit 4 files. Pretty sure it satisfies all your requirements stated above

VerticalLinearStepper.js: this is where we store our username, password, disabledNext (radioButton) state and handleChange method for setState. Then, we passed down the state to -> Step1.js -> AsyncValidationForm.js.

classVerticalLinearStepperextendsReact.Component {
  state = {
    activeStep: 0,
    //we set our state in this parentdisabledNext: true,
    username: "",
    password: ""
  };

  steps = {
    "Select campaign settings": Step1,
    "Create an ad group": Step2,
    "Create an ad": Step3
  };

  //setState for disabledNext
  handleChangeDisabledNext = value => {
    this.setState({ disabledNext: value });
  };
  //setState for username, password
  handleChange = (name, value) => {
    this.setState({ [name]: value });
  };

  stepsCount = () =>Object.values(this.steps).length;

  canGoBack = () =>this.state.activeStep > 0;
  canGoForward = () =>this.state.activeStep < this.stepsCount();

  isFinished = () =>this.state.activeStep === this.stepsCount();

  handleBack = () => {
    if (this.canGoBack()) {
      this.setState(prevState => ({ activeStep: prevState.activeStep - 1 }));
    }
  };

  handleNext = () => {
    if (this.canGoForward()) {
      this.setState(prevState => ({ activeStep: prevState.activeStep + 1 }));
    }
  };

  handleReset = () =>this.setState({ activeStep: 0 });

  render() {
    const { classes } = this.props;
    const { activeStep } = this.state;

    return (
      <divclassName={classes.root}><StepperactiveStep={activeStep}orientation="vertical">
          {Object.entries(this.steps).map(([label, CustomStep]) => (
            <Stepkey={label}><StepLabel>{label}</StepLabel><StepContent><CustomStepcanGoBack={this.canGoBack()}canGoForward={this.canGoForward()}onBack={this.handleBack}onNext={this.handleNext}classes={classes}
                  //wepassdownthestateandits' setStatemethodhandleChangeDisabledNext={this.handleChangeDisabledNext}disabledNext={this.state.disabledNext}handleChange={this.handleChange}username={this.state.username}password={this.state.password}
                /></StepContent></Step>
          ))}
        </Stepper>

        {this.isFinished() && (
          <Papersquareelevation={0}className={classes.resetContainer}><Typography>All steps completed - you&apos;re finished</Typography><ButtononClick={this.handleReset}className={classes.button}>
              Reset
            </Button></Paper>
        )}
      </div>
    );
  }
}

In AsyncValidationForm.js, we bind onChange method to track the value and call the setState method and this.props.handleChange for setState in VerticalLinearStepper.js

const renderField = ({
  input,
  label,
  type,
  //checked is for radio, initialValue is for setting the username, password value
  checked,
  initialValue,
  meta: { asyncValidating, touched, error }
}) => {
  return (
    <div>
      <label>{label}</label>
      <div className={asyncValidating ? "async-validating" : ""}>
        <input
          {...input}
          value={initialValue} //add value attr
          checked={checked} //add checked attr
          type={type}
          placeholder={label}
        />
        {touched && error && <span>{error}</span>}
      </div>
    </div>
  );
};

classAsyncValidationFormextendsReact.Component{
  constructor(props) {
    super(props);
    console.log("AsyncValidationForm ---->");

    this.state = {
      //pass down VerticalLinearStepper.js state if any
      username: this.props.username ? this.props.username : "",
      password: this.props.password ? this.props.password : "",
      //this determines whether any fields is filled or not from VerticalLinearStepper
      pristine:
        this.props.username || this.props.password || !this.props.disabledNext
          ? false
          : true
    };
  }

  passRadioValue = e => {
    this.setState({ pristine: false }, () => {
      this.props.handleChangeDisabledNext(!e.target.checked);
    });
  };

  handleChange = name => event => {
    const value = event.target.value;
    this.setState(
      {
        [name]: value,
        pristine: false
      },
      () => {
        this.props.handleChange(name, value); //setState username, password of VerticalLinearStepper.js
      }
    );
  };

  resetForm = () => {
    this.props.handleChangeDisabledNext(true); //setState disabledNext of VerticalLinearStepper.jsthis.setState(
      {
        username: "",
        password: "",
        pristine: true
      },
      () => {
        this.props.handleChange("username", "");
        this.props.handleChange("password", "");
      }
    );

    this.props.reset();
  };

  // this.setState({ disabled: !this.state.disabled });

  render() {
    const { handleSubmit, pristine, reset, submitting } = this.props;

    return (
      <form onSubmit={handleSubmit}>
        <Field
          name="username"
          type="text"
          component={renderField}
          label="Username"
          initialValue={this.state.username}
          onChange={this.handleChange("username")}
        />
        <Field
          name="password"
          type="password"
          component={renderField}
          label="Password"
          initialValue={this.state.password}
          onChange={this.handleChange("password")}
        />

        <label>
          <Field
            name="sex"
            component={renderField}
            type="radio"
            value="male"
            checked={!this.props.disabledNext}
            onChange={this.passRadioValue}
          />{" "}
          Male
        </label>

        <div>
          <button type="submit" disabled={submitting}>
            Sign Up
          </button>
          <button
            type="button"
            disabled={(pristine || submitting) && this.state.pristine} //add state.pristine checking
            onClick={this.resetForm}
          >
            Clear Values
          </button>
        </div>
      </form>
    );
  }
}

Then, in StepTemplate.js Add disabledNext, checkDisabledNext props. checkDisabledNext to determine whether the Next Button will have conditional checking or not. disabledNext is the disabled value.

constStepTemplate = ({
  classes,
  canGoBack,
  canGoForward,
  onBack,
  onNext,
  text,
  children,
  //we pass down these 2 values
  disabledNext,
  checkDisabledNext
}) => (
  <Fragment><Typography>{text}</Typography><divclassName={classes.actionsContainer}><div>
        {children}

        <Buttondisabled={!canGoBack}onClick={onBack}className={classes.button}
        >
          Back
        </Button><Buttonvariant="contained"color="primary"onClick={onNext}className={classes.button}
          //determinewhetherweshouldcheckbuttondisabledornotdisabled={checkDisabledNext ? disabledNext:false}
        >
          {canGoBack ? "Next" : "go to next step"}
        </Button></div></div></Fragment>
);

This is Step1.js, here we just pass props to StepTemplate and AsyncValidationForm:

const Step = props => (
  <StepTemplate
    text={`
        For each ad campaign that you create, you can control how much you're
        willing to spend on clicks and conversions, which networks and
        geographical locations you want your ads to show on, and more.

        For each ad campaign that you create, you can control how much you're
        willing to spend on clicks and conversions, which networks and
        geographical locations you want your ads to show on, and more.

        For each ad campaign that you create, you can control how much you're
        willing to spend on clicks and conversions, which networks and
        geographical locations you want your ads to show on, and more.

        For each ad campaign that you create, you can control how much you're
        willing to spend on clicks and conversions, which networks and
        geographical locations you want your ads to show on, and more.

        For each ad campaign that you create, you can control how much you're
        willing to spend on clicks and conversions, which networks and
        geographical locations you want your ads to show on, and more.

        For each ad campaign that you create, you can control how much you're
        willing to spend on clicks and conversions, which networks and
        geographical locations you want your ads to show on, and more.

        For each ad campaign that you create, you can control how much you're
        willing to spend on clicks and conversions, which networks and
        geographical locations you want your ads to show on, and more.

        For each ad campaign that you create, you can control how much you're
        willing to spend on clicks and conversions, which networks and
        geographical locations you want your ads to show on, and more.

        For each ad campaign that you create, you can control how much you're
        willing to spend on clicks and conversions, which networks and
        geographical locations you want your ads to show on, and more.

        For each ad campaign that you create, you can control how much you're
        willing to spend on clicks and conversions, which networks and
        geographical locations you want your ads to show on, and more.

        For each ad campaign that you create, you can control how much you're
        willing to spend on clicks and conversions, which networks and
        geographical locations you want your ads to show on, and more.

        For each ad campaign that you create, you can control how much you're
        willing to spend on clicks and conversions, which networks and
        geographical locations you want your ads to show on, and more.
    `}
    //we want to apply checking on Step1.js, so we add checkDisabledNext attribute
    checkDisabledNext={true}
    // disabledNext={this.props.disabledNext} //no need to do this because will be passed with  {...props} below
    {...props}
  >
    <form>
      form for the first step here
      <div>test here</div>
      <AsyncValidationForm
        onSubmit={values => {
          console.log(values);
          alert(
            `Values: username: ${values.username} password: ${values.password}`
          );
        }}
        //these are the props passed down from VerticalLinearStepper.js
        handleChangeDisabledNext={props.handleChangeDisabledNext}
        disabledNext={props.disabledNext}
        handleChange={props.handleChange}
        username={props.username}
        password={props.password}
      />
    </form>
  </StepTemplate>
);

Here is the re-render issue fix: https://codesandbox.io/s/vqvxj7ky4y Update VerticalLinearStepper.js, then we dont need Step1.js file anymore, since we write the content of Step1.js in this file:

importReactfrom"react";
importPropTypesfrom"prop-types";
import { withStyles } from"@material-ui/core/styles";
importStepperfrom"@material-ui/core/Stepper";
importStepfrom"@material-ui/core/Step";
importStepLabelfrom"@material-ui/core/StepLabel";
importStepContentfrom"@material-ui/core/StepContent";
importButtonfrom"@material-ui/core/Button";
importPaperfrom"@material-ui/core/Paper";
importTypographyfrom"@material-ui/core/Typography";

// import Step1 from "./steps/Step1";importStep2from"./steps/Step2";
importStep3from"./steps/Step3";

importStepTemplatefrom"./steps/StepTemplate";
importAsyncValidationFormfrom"./forms/AsyncValidationForm";

conststyles = theme => ({
  root: {
    width: "90%"
  },
  button: {
    marginTop: theme.spacing.unit,
    marginRight: theme.spacing.unit
  },
  actionsContainer: {
    marginBottom: theme.spacing.unit * 2
  },
  resetContainer: {
    padding: theme.spacing.unit * 3
  }
});

classVerticalLinearStepperextendsReact.Component {
  state = {
    activeStep: 0,
    //we set our state in this parentdisabledNext: true,
    username: "",
    password: ""
  };

  steps = {
    //we pass the content of Step1 here, so we dont have to pass props"Select campaign settings": props => (
      <StepTemplatetext={`
        Foreachadcampaignthatyoucreate, youcancontrolhowmuchyou'rewillingtospendonclicksandconversions, whichnetworksandgeographicallocationsyouwantyouradstoshowon, andmore.Foreachadcampaignthatyoucreate, youcancontrolhowmuchyou'rewillingtospendonclicksandconversions, whichnetworksandgeographicallocationsyouwantyouradstoshowon, andmore.Foreachadcampaignthatyoucreate, youcancontrolhowmuchyou'rewillingtospendonclicksandconversions, whichnetworksandgeographicallocationsyouwantyouradstoshowon, andmore.Foreachadcampaignthatyoucreate, youcancontrolhowmuchyou'rewillingtospendonclicksandconversions, whichnetworksandgeographicallocationsyouwantyouradstoshowon, andmore.Foreachadcampaignthatyoucreate, youcancontrolhowmuchyou'rewillingtospendonclicksandconversions, whichnetworksandgeographicallocationsyouwantyouradstoshowon, andmore.Foreachadcampaignthatyoucreate, youcancontrolhowmuchyou'rewillingtospendonclicksandconversions, whichnetworksandgeographicallocationsyouwantyouradstoshowon, andmore.Foreachadcampaignthatyoucreate, youcancontrolhowmuchyou'rewillingtospendonclicksandconversions, whichnetworksandgeographicallocationsyouwantyouradstoshowon, andmore.Foreachadcampaignthatyoucreate, youcancontrolhowmuchyou'rewillingtospendonclicksandconversions, whichnetworksandgeographicallocationsyouwantyouradstoshowon, andmore.Foreachadcampaignthatyoucreate, youcancontrolhowmuchyou'rewillingtospendonclicksandconversions, whichnetworksandgeographicallocationsyouwantyouradstoshowon, andmore.Foreachadcampaignthatyoucreate, youcancontrolhowmuchyou'rewillingtospendonclicksandconversions, whichnetworksandgeographicallocationsyouwantyouradstoshowon, andmore.Foreachadcampaignthatyoucreate, youcancontrolhowmuchyou'rewillingtospendonclicksandconversions, whichnetworksandgeographicallocationsyouwantyouradstoshowon, andmore.Foreachadcampaignthatyoucreate, youcancontrolhowmuchyou'rewillingtospendonclicksandconversions, whichnetworksandgeographicallocationsyouwantyouradstoshowon, andmore.
    `}
        //wewanttoapplycheckingonStep1.js, soweaddcheckDisabledNextattributecheckDisabledNext={true}disabledNext={this.state.disabledNext} //usethisclass' state
        {...props}
      ><form>
          form for the first step here
          <div>test here</div><AsyncValidationFormonSubmit={values => {
              console.log(values);
              alert(
                `Values: username: ${values.username} password: ${
                  values.password
                }`
              );
            }}
            //we use this class setstate , no need to pass down props
            handleChangeDisabledNext={this.handleChangeDisabledNext}
            disabledNext={this.state.disabledNext}
            handleChange={this.handleChange}
            username={this.state.username}
            password={this.state.password}
          />
        </form></StepTemplate>
    ),
    "Create an ad group": Step2,
    "Create an ad": Step3
  };

  //setState for disabledNext
  handleChangeDisabledNext = value => {
    this.setState({ disabledNext: value });
  };
  //setState for username, password
  handleChange = (name, value) => {
    this.setState({ [name]: value });
  };

  stepsCount = () =>Object.values(this.steps).length;

  canGoBack = () =>this.state.activeStep > 0;
  canGoForward = () =>this.state.activeStep < this.stepsCount();

  isFinished = () =>this.state.activeStep === this.stepsCount();

  handleBack = () => {
    if (this.canGoBack()) {
      this.setState(prevState => ({ activeStep: prevState.activeStep - 1 }));
    }
  };

  handleNext = () => {
    if (this.canGoForward()) {
      this.setState(prevState => ({ activeStep: prevState.activeStep + 1 }));
    }
  };

  handleReset = () =>this.setState({ activeStep: 0 });

  render() {
    const { classes } = this.props;
    const { activeStep } = this.state;

    return (
      <divclassName={classes.root}><StepperactiveStep={activeStep}orientation="vertical">
          {Object.entries(this.steps).map(([label, CustomStep]) => (
            <Stepkey={label}><StepLabel>{label}</StepLabel><StepContent><CustomStepcanGoBack={this.canGoBack()}canGoForward={this.canGoForward()}onBack={this.handleBack}onNext={this.handleNext}classes={classes}
                /></StepContent></Step>
          ))}
        </Stepper>

        {this.isFinished() && (
          <Papersquareelevation={0}className={classes.resetContainer}><Typography>All steps completed - you&apos;re finished</Typography><ButtononClick={this.handleReset}className={classes.button}>
              Reset
            </Button></Paper>
        )}
      </div>
    );
  }
}

VerticalLinearStepper.propTypes = {
  classes: PropTypes.object
};

exportdefaultwithStyles(styles)(VerticalLinearStepper);

Additional reference: React: Class Component vs Functional Component

Solution 2:

This is a simple code to enable a button on radio button click If you want a more descriptive one please elaborate your question

<html><script>functionenableButton()
{
	document.getElementById("button").disabled = true;
}
</script><inputtype="radio"name="gender"value="male"onclick="JaaScript:enableButton()"> Male<br><buttontype="button"id="button">Click Me!</button></html>

Solution 3:

First thing you will need to do is remove the reference to this from your functional component...

onClick={this.passRadioValue("right")}

TO

onClick={passRadioValue("right")}

Functional components inherit their functional context from the parent function's scope and don't have a this object. this will remove the immediate errors

Here's is a forked version or your codepen I've started for reference...

https://codesandbox.io/s/4jpkk394x7?moduleview=1

And some background on Functional (stateless) vs Class (stateful) components...

https://programmingwithmosh.com/react/react-functional-components/

Post a Comment for "Enable The Go To Next Step Button, Tried Setting Up State And Created New Onclick Method In The Radio Button"