skip to Main Content

I am trying to have a button enabled in a modal when text is entered in an input field. But my form is built in another class and is used in a parent class. How can I pass an onChange method my form component.

Here is my parent component:

import React from 'react';
import {
  Button,
  Dialog,
  DialogActions,
  DialogContent,
  DialogTitle
} from '@material-ui/core';
import CompanyFinancialModalForm from '../CompanyFinancialModalForm/CompanyFinancialModalForm';

interface CompanyFinancialModalState {
  addEnabled: boolean;
}

interface CompanyFinancialModalProps {
  open: boolean;
  onClose: () => void;
}

export class CompanyFinancialModal extends React.Component<
  CompanyFinancialModalProps,
  CompanyFinancialModalState
> {
  constructor(props: CompanyFinancialModalProps) {
    super(props);

    this.state = {
      addEnabled: false
    };
  }

  private enableButton = () => {
    this.setState({ addEnabled: true});
  }

  public render() {
    const { open, onClose } = this.props;
    const { addEnabled } = this.state;
    return (
      <>
        <Dialog
          open={open}
          onClose={onClose}
          className="company-financial-modal"
        >
          <DialogTitle id="company-financial-modal-title">
            {'Company and Financial Data'}
          </DialogTitle>
          <DialogContent>
            <CompanyFinancialModalForm onChange={this.enableButton}/>
          </DialogContent>
          <DialogActions>
            <Button
              id="company-financial-modal-add"
              disabled={!addEnabled}
              onClick={onClose}
              color="primary"
            >
              Add
            </Button>
            <Button
              id="company-financial-modal-cancel"
              onClick={onClose}
              color="secondary"
              autoFocus={true}
            >
              Cancel
            </Button>
          </DialogActions>
        </Dialog>
      </>
    );
  }
}

export default CompanyFinancialModal;

Here is my class that my form is in:

import React from 'react';
import axios from 'axios';
import { Form, Field } from 'react-final-form';
import { TextField, Select } from 'final-form-material-ui';
import {
  Paper,
  Grid,
  MenuItem,
} from '@material-ui/core';

export interface IValues {
  company_name: string;
  critical_technology: [];
}
export interface IFormState {
  [key: string]: any;
  values: IValues[];
  submitSuccess: boolean;
}

export default class CompanyFinancialModalForm extends React.Component<{}, IFormState> {
  constructor(props: {}) {
    super(props);
    this.state = {
      company_name: '',
      critical_technology: [],
      values: [],
      submitSuccess: false
    };
  }

  private processFormSubmission = (e: React.FormEvent<HTMLFormElement>): void => {
    e.preventDefault();
    this.setState({ loading: true });
    const formData = {
      company_name: this.state.company_name,
      critical_technology: this.state.critical_technology
    };
    this.setState({
      submitSuccess: true,
      values: [...this.state.values, formData],
      loading: false
    });
    axios.post(`http://localhost:8081/companies`, formData);
  }

  private onChange = (e: React.FormEvent<HTMLInputElement>) => {
    const { name, value } = e.target;
    // other form-related logic
    this.props.onChange({ name, value }, e);
  }

  public render() {
    const { submitSuccess, loading } = this.state;
    const { onChange } = this.props;
    return (
      <div>
        <Form
          onSubmit={this.processFormSubmission}
          // validate={this.validateForm}
          render={({ handleSubmit,/*  reset,  submitting, pristine, values*/ }) => (
          <form onSubmit={handleSubmit} noValidate>
            <Paper style={{ padding: 16 }}>
              <Grid container alignItems="flex-start" spacing={2}>
                <Grid item xs={6}>
                  <Field
                    fullWidth
                    required
                    name="companyName"
                    component={TextField}
                    type="text"
                    label="Company Name"
                    onChange={onChange}
                  />
                </Grid>                
                <Grid item xs={12}>
                  <Field
                    name="critical_technology"
                    label="Critical Technology"
                    component={Select as any}
                  >
                    <MenuItem value="hypersonics">Hypersonics</MenuItem>
                    <MenuItem value="directed_energy">Directed Energy</MenuItem>
                    <MenuItem value="command_control_and_communications">Command, Control and Communications </MenuItem>
                    <MenuItem value="space_offense_and_defense">Space Offense and Defense</MenuItem>
                    <MenuItem value="cybersecurity">Cybersecurity</MenuItem>
                    <MenuItem value="artificial_intelligence_machine_learning">Artificial Intelligence/Machine Learning</MenuItem>
                    <MenuItem value="missile_defense">Missile Defense</MenuItem>
                    <MenuItem value="quantum_science_and_computing">Quantum Science and Computing </MenuItem>
                    <MenuItem value="microelectronics">Microelectronics</MenuItem>
                    <MenuItem value="autonomy">Autonomy</MenuItem>
                  </Field>
                </Grid>
              </Grid>
            </Paper>
          </form>
        )}
      />
      </div>
    );
  }
}

I want to pass a prop to <CompanyFinancialModalForm /> that enables the add button when the Textfield has text typed into it.

2

Answers


  1. For future reference, it will be more beneficial if you only include the relevant code, because it takes more time to find when scrolling through irrelevant code, anyways:

    I’m not 100% clear on what you’re looking for, but I’ll try to answer what I think I understand. You can add an onChange method on your parent component, and pass that as a prop to the form, and the form can call that function every time it runs it’s own onChange method. Below is a simplified version:

    class Parent extends Component {
      state = { 
        buttonEnabled: false,
        // formInputValue: '', <-- if you need this
      };
    
      // - omitting constructor/bind for simplicity for now
      onChange({ name, value }, e) {
        // your logic to determine whether button is enabled or not
        // this is just me guessing what you want to implement
        if (value) this.setState({ buttonEnabled: true });
        else this.setState({ buttonEnabled: false });
      }
    
      render() {
        return (
          <Fragment>
            <YourForm onChange={this.onChange} />
            <Button enabled={this.state.buttonEnabled} />
          </Fragment>
        );
      }
    }
    
    class YourForm extends Component {
      onChange(e) {
        const { name, value } = e.target;
        // other form-related logic
        this.props.onChange({ name, value }, e);
      }
    }
    

    is this what you’re looking for?

    Login or Signup to reply.
  2. You can simply pass a child a reference to a function that exists in the parent and then use the parent’s function to validate and enable the button.

    Codesandbox Demo

    Simplified Code:

    function Child (props) {
      return (
        <input type="text" onChange={props.doIt}/>
      )
    }
    
    function App() {
     const [disabled, setDisabled] = useState(true);
    
     function doIt(e) {
         setDisabled(e.currentTarget.value.length === 0);
     }
      return (
        <div className="App">
          <h1>Hello CodeSandbox</h1>
          <Child doIt={doIt} />
          <button disabled={disabled}>Add</button>
        </div>
      );
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search