DEV Community

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

Create a FormBuilder component in React Native (Part 7)

This series contents:

Part 7: Add support for Boolean field type

Now that we verified that our FormBuilder worked perfectly fine while creating a new form, let's see how we can add support for a new field type - a Boolean field in our case.

Create a new FormBooleanInput component

Let's start by creating a new custom component which will render out a Boolean field for us. We'll call it FormBooleanInput:

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

/**
 * A stateless function component which renders a Boolean input (Switch).
 *
 * @param {obj} props
 */
const FormBooleanInput = (props) => {
    const { labelText, ...inputProps } = props;

    return (
        <View style={styles.switchWrapper}>
            <Switch {...inputProps} />
            {labelText && <Text style={styles.label}>{labelText}</Text>}
        </View>
    );
};

FormBooleanInput.propTypes = {
    labelText: PropTypes.string,
};

FormBooleanInput.defaultProps = {
    labelText: null,
};

const styles = StyleSheet.create({
    switchWrapper: {
        flex: 1,
        marginBottom: 15,
        paddingHorizontal: 10,
        flexDirection: 'row',
        alignItems: 'center',
    },
    label: {
        flex: 1,
        color: '#FFF',
        marginLeft: 10,
    },
});

export default FormBooleanInput;

As you can see it's a pretty basic component which renders out a Switch React Native component along with a label (if provided).

Add a new field to the Sign Up form

Let's use the Sign Up form we created in our last post and add a new field to it, which hypothetically will allow users to subscribe to a mailing list. The field's "definition" would look like this:

[
    {
        name: 'subscribe',
        label: 'Subscribe me to weekly news from Tech world.',
        type: 'boolean',
        defaultValue: true,
    },
]

You've probably noticed the new defaultValue field property. We'll use it to allow us having default values for any of our form fields. See the next section for details about how we'll be implementing this logic.

Add support for the boolean field within the FormBuilder component

Here we'll need to work on a couple of changes:

  • Allow form fields to have predefined default values by using the defaultValue field's property. Let's create a helper function which will detect for us what should be the default value for a given field.
/**
 * Determine what should be the default value
 * for a given field.
 */
getFormFieldDefaultValue = ({ defaultValue, type }) => {
    if (defaultValue !== undefined) {
        return defaultValue;
    }

    switch (type) {
    case 'boolean':
        return false;
    default:
        return '';
    }
};

Now we can make use of this function within our constructor() like so:

const formFieldNames = formFields.reduce((obj, field) => {
    obj[field.name] = this.getFormFieldDefaultValue(field);
    return obj;
}, {});
  • Update our hasValidFormData() helper function to ignore boolean field types simply because this type of fields will always have a value (either true or false). The updated version looks like this:
hasValidFormData = () => {
    const formFields = this.getFormFields();
    const isFilled = formFields
        // filter out Boolean fields because they will always have a value
        .filter(field => field.type !== 'boolean')
        // check if all remaining fields have been filled out
        .every(field => !!this.state[field.name]);

    return isFilled;
};
  • Update our hasDirtyFormData() helper function and use a different approach for detecting if a boolean field changed its value or not, like so:
hasDirtyFormData = () => {
    const formFields = this.getFormFields();
    const isDirty = formFields.some((field) => {
        switch (field.type) {
        case 'boolean':
            // because Boolean fields will have a default value,
            // we need to check if the current value is not the default one
            return this.state[field.name] !== this.getFormFieldDefaultValue(field);

        default:
            return !!this.state[field.name];
        }
    });

    return isDirty;
};
  • Create a new renderBooleanInput() helper function which will render out the FormBooleanInput component for us. The function it's not very different from the existing renderTextInput(). Probably the main difference is using onValueChange prop instead of onChangeText.
renderBooleanInput = ({ name, label, inputProps }) => (
    <FormBooleanInput
        {...inputProps}
        value={this.state[name]}
        onValueChange={(value) => {
            this.setState({ [name]: value });
        }}
        labelText={label}
        key={name}
    />
);
  • And lastly, let's update our component's render() function and render out boolean fields (if any were provided).
{formFieldsRows.map((formFieldsRow, i) => (
    <View style={styles.row} key={`r-${i}`}>
        {formFieldsRow.map((field) => {
            switch (field.type) {
            case 'boolean':
                return this.renderBooleanInput(field);

            default:
                return this.renderTextInput(field);
            }
        })}
    </View>
))}

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

Sign Up Form V2

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


That's it my friends! πŸ™‚πŸš€πŸš’ I think we've covered enough content to give you an idea on how to build your own FormBuilder component from scratch. πŸ—οΈ Even though I'm going finish this series here, there are still so many things we can apply to this helper component (e.g. support for optional fields, support for new field types, etc.), but let's consider that as homework for you πŸ‘¨β€πŸ’»πŸ‘©β€πŸ’».


Bonus links 🎁

Here are some good resources I used to get started with React Native:

Packages:

App Icons + Splash Screens setup (that's always a tricky part so the links below definitely helped me):

Happy coding! πŸ‘¨β€πŸ’»πŸ‘©β€πŸ’»πŸ‘

Oldest comments (0)