DEV Community

Cover image for Create a FormBuilder component in React Native (Part 5)

Create a FormBuilder component in React Native (Part 5)

This series contents:

Part 5: Enable/disable form buttons on-the-fly

Wouldn't be nice to have our form buttons enabled only when we need? For example:

  • disable the Calculate button by default, and only enable it when all form fields have been filled out;
  • disable the Reset button by default as well, and only enable it when at least one form field has been filled out.

Modify our FormButton component

Let's take care of that. First of all, we need to modify our FormButton component and allow it to accept a boolean disabled prop which will use to enable or disable our button. The modified version looks like this:

import React from 'react';
import PropTypes from 'prop-types';
import { TouchableOpacity, Text, StyleSheet } from 'react-native';

/**
 * A stateless function component which renders a button.
 *
 * @param {obj} props
 */
const FormButton = (props) => {
    const { children, onPress, disabled } = props;

    return (
        <TouchableOpacity
            style={[styles.button, disabled && styles.buttonDisabled]}
            onPress={onPress}
            disabled={disabled}
        >
            <Text style={styles.buttonText}>{children}</Text>
        </TouchableOpacity>
    );
};

FormButton.propTypes = {
    onPress: PropTypes.func,
    children: PropTypes.string.isRequired,
    disabled: PropTypes.bool,
};

FormButton.defaultProps = {
    onPress: f => f,
    disabled: false,
};

const styles = StyleSheet.create({
    button: {
        backgroundColor: '#FD6592',
        borderRadius: 3,
        height: 40,
        marginHorizontal: 10,
        marginBottom: 15,
        justifyContent: 'center',
        alignItems: 'center',
    },
    buttonText: {
        color: '#FFF',
        fontWeight: 'bold',
        fontSize: 16,
    },
    buttonDisabled: {
        opacity: 0.5,
    },
});

export default FormButton;

TouchableOpacity accepts a boolean disabled prop and when it's true, it disables all interactions for this component. This is exactly what we need with one small exception: visually the button looks the same in both enabled and disabled states. We can fix that by conditionally adding some styles when the disabled prop is true like so (please note that I have replaced some existing code with comments just to highlight the changes we've made):

<TouchableOpacity
   style={[styles.button, disabled && styles.buttonDisabled]}
   {/* ... */}

const styles = StyleSheet.create({
    // ...
    buttonDisabled: {
        opacity: 0.5,
    },
});

Enable/disable the Calculate button

As we mentioned above, we want our Calculate button to be enabled only when all form fields have been filled out. Well, we already have our hasValidFormData helper function which can tell us exactly that. We can use it like so:

<FormButton
    onPress={this.attemptFormSubmission}
    disabled={!this.hasValidFormData()}
>
    {submitBtnTitle}
</FormButton>

Enable/disable the Reset button

This button needs to be enabled when at least one form field has been filled out. Let's write a little helper function which can help us detect that:

/**
 * Check if at least one field has been filled out.
 */
hasDirtyFormData = () => {
    const formFields = this.getFormFields();
    const isDirty = formFields.some(field => !!this.state[field.name]);
    return isDirty;
};

Note how we're making use of the JavaScript Array some() method - very handy for our use-case.

Now we're ready to enable and disable the Reset button on-the-fly like so:

<FormButton onPress={this.resetForm} disabled={!this.hasDirtyFormData()}>
    Reset
</FormButton>

That's it! Let's take a look at how the form works at this point:

Salary Calculator V3

For a full list of changes, check out this commit on GitHub.


Great job if you made it so far!πŸ‘ But why stop here? πŸ€“ Let's try our component in action one more time and use it to create a Sign Up form in Part 6 of this series πŸ‘‰.

Top comments (0)