Source:  Twitter logo

I'm rendering the below simple form using redux-form and it's working nicely. Now, I'd like to have the submit button disabled in one more situation: If any of the Field's has an error (i.e. it's meta.error is set).

From lokking into the docs, I suppose it is not possible for the surrounding <form> to know if its <Field> components have an error. Maybe anyone has an idea, how to solve it as easy as using disabled={hasErrors || submitting || pristine}

const EditBlogEntryForm = ({ onSubmit, reset, handleSubmit,
                         pristine, submitting, ...rest }) => {
    console.log('rest: ', rest);
    return (
        <form onSubmit={handleSubmit(onSubmit)}>
            <div className="form-group">
                <Field name="title"
                    type="text"
                    component={renderField}
                    label="Titel"
                    className="form-control"
                    placeholder="Titel eingeben..." />
            </div>
            <div className="form-group">
                <Field name="text"
                    component={renderTextArea}
                    label="Text"
                    className="form-control"
                    placeholder="Textinhalt eingeben..." />
            </div>  
            <div className="form-group">
                <Field name="image"
                    type="text"
                    component={renderField}
                    label="Bild-URL:"
                    className="form-control"
                    placeholder="Bildadresse eingeben..." />
            </div>  
            <div>
                <button type="submit" className="btn btn-default"
                    disabled={submitting || pristine}>
                    Blogeintrag speichern
                </button>
                <button type="button" className="btn btn-default"
                    disabled={pristine || submitting}
                    onClick={reset}>
                    Formular leeren
                </button>
            </div>
        </form>
    );
};

Don't abuse state you need just using this.props for each setState Component one more time will be render

const {invalid} = this.props

return(
<button type="submit" className="btn btn-default"
     disabled={invalid|| submitting || pristine}>
     Blogeintrag speichern
 </button>)

More Document: https://redux-form.com/6.0.0-alpha.4/docs/api/props.md/

27 users liked answer #0dislike answer #027
masoud soroush profile pic
masoud soroush

Redux forms already passes lots of properties into the form. One is invalid. That's what I am using to determine if any of the field validations failed and then disable submit.

https://redux-form.com/6.0.0-alpha.4/docs/api/props.md/

3 users liked answer #1dislike answer #13
Nick Graham profile pic
Nick Graham

What you should be able to do is just have a variables called Errors that will be true once your api call comes back with an error

 constructor(super) {
      this.state = {
         errors: false,
      }
 }

 componentWillReceiveProps(nextProps) {
     const that = this;
     if (nextProps.errors) {
        that.setState({errors: true})
     }    
 }

 <button type="submit" className="btn btn-default"
     disabled={this.state.errors || submitting || pristine}>
     Blogeintrag speichern
 </button>
2 users liked answer #2dislike answer #22
Alastair profile pic
Alastair

Alastair pointed me into the correct direction (Thanks for that!). I guess this is one of the cases where a local UI-related state is actually very useful. So I refactored the SFC into a react class. That classes' constructor and componentWillReceiveProps look like this:

constructor(props) {
    super(props);
    this.state = {
        errors: false
    };
}

componentWillReceiveProps(nextProps) {
    if (nextProps.invalid) {
        this.setState({errors: true});
    } else {
        this.setState({errors: false});
    }
}

Now using this.state.errors to have the button disabled is working perfectly. As you can see, I had to use the invalid prop form redux-form, because its error prop was always undefined and not to forget to set it true again, if the form is valid. Furthermore I don't know, why you copied the this reference into that in your answer. It wouldn't change any behaviour as it's still pointing to the same object.

0 users liked answer #3dislike answer #30
Christof Kälin profile pic
Christof Kälin

If you are using the react-redux-form library you can eventually use the onUpdate event on the form to capture the validity state of the form and like this you can change some internal state variable which can be used to deactivate a button. Here is some sample code to demonstrate what you can do:

import React, { Component } from 'react';
import { Button, Modal, ModalHeader, ModalBody, Row, Label, Col } from 'reactstrap';
import { Control, LocalForm, Errors } from 'react-redux-form';

const required = (val) => val && val.length;

const maxLength = (len) => (val) => !(val) || (val.length <= len);

const minLength = (len) => (val) => (val) && (val.length >= len);

class CommentForm extends Component {

    constructor(props) {
        super(props);
        this.state = {
            isModalOpen: false,
            isFormInValid: true
        };
        this.toggleModal = this.toggleModal.bind(this);
    }

    toggleModal() {
        this.setState({
            isModalOpen: !this.state.isModalOpen
        })
    }

    handleSubmit(values) {
        console.log("Current state is: " + JSON.stringify(values));
        alert(JSON.stringify(values));
    }

    handleUpdate(form) {
        this.setState({ isFormInValid: !form['$form'].valid });
    }

    render() {
        return (
            <>
                <Button outline onClick={this.toggleModal}>
                    <span className="fa fa-pencil fa-lg"></span> Submit Comment
                </Button>
                <Modal isOpen={this.state.isModalOpen} toggle={this.toggleModal}>
                    <ModalHeader toggle={this.toggleModal}>Submit Comment</ModalHeader>
                    <ModalBody>
                        <LocalForm
                            onUpdate={(form) => this.handleUpdate(form)}
                            onSubmit={(values) => this.handleSubmit(values)}>
                            <Row className="form-group">
                                <Label htmlFor="author" md={12}>Your Name</Label>
                                <Col md={12}>
                                    <Control.text model=".author" id="author" name="author"
                                        placeholder="First Name" className="form-control"
                                        validators={{ required, minLength: minLength(3), maxLength: maxLength(15) }} />
                                    <Errors className="text-danger" model=".author" show="touched"
                                        messages={{ required: 'Required ', minLength: 'Must be greater than 2 characters', maxLength: 'Must be 15 characters or less' }} />
                                </Col>
                            </Row>
                            <Row className="form-group">
                                <Col md={12}>
                                    <Button type="submit" color="primary" disabled={this.state.isFormInValid}>Submit</Button>
                                </Col>
                            </Row>
                        </LocalForm>
                    </ModalBody>
                </Modal>
            </>
        );
    }
}
0 users liked answer #4dislike answer #40
gil.fernandes profile pic
gil.fernandes

This is an update for Masoud Soroush's answer.

Checking the invalid prop only is enough.

const {invalid} = this.props

return(
<button type="submit" className="btn btn-default"
     disabled={invalid}>
     Blogeintrag speichern
</button>

Note: Use the submitting prop only if you have passed an onSubmit function that returns a promise. It will be true until the promise is resolved or rejected.

0 users liked answer #5dislike answer #50
Ankush Chauhan profile pic
Ankush Chauhan

A possibility is to use validate field. You need to defined a function :

const required = value => (value ? undefined : 'Required')

And use this function in your field :

           <div className="form-group">
                <Field name="title"
                    type="text"
                    component={renderField}
                    label="Titel"
                    className="form-control"
                    placeholder="Titel eingeben..."
                    validate={[required]}
                />
            </div>
-2 users liked answer #6dislike answer #6-2
morgane1806 profile pic
morgane1806

Copyright © 2022 QueryThreads

All content on Query Threads is licensed under the Creative Commons Attribution-ShareAlike 3.0 license (CC BY-SA 3.0).