formbus

0.5.2 • Public • Published

FormBus

FormBus is what you are looking for if you do server-side form validation, and you want a plug and play front-end solution to do the typical.

You can use the built-in directives to show or toggle CSS class names when the fields validation failed, or when the submission was successful, or something went wrong.

In the WordPress context, FormBus is suitable when you are using a forms plugin and:

  1. The generated HTML structure does not suit your needs, or you are using utility-first CSS frameworks like Tailwind CSS, and you wish to use those class names
  2. You are deep into the rabbit hole of front-end optimization, and you don't want any bloated libraries or dependencies that you are not using anywhere else, like jQuery
  3. You are using WordPress as a headless CMS, and you are using the REST API as a primary way to interact with it

FormBus demo with Contact Form 7

Check out the video demonstration


Usage

Installation

The recommended way of installing FormBus is using npm:

npm install formbus

Submitting your form

As long as your form element is set up correctly:

  1. action is pointing to the API endpoint
  2. method is set to to post
  3. input elements have the name attribute

FormBus is able to construct the request and send it. It uses Fetch API, and the data is constructed using FormData.

If you need to set additional configuration values, for example, headers, you can use the configuration object. It's explained later in the documentation.

<form action="https://your-website.com/wp-json/contact-form-7/v1/contact-forms/<ID>/feedback"
      method="post"
      id="contact-form">
    <div class="form-group">
        <label for="name">Your Name</label>
        <input type="text" name="your-name" class="form-control" id="name">
    </div>
    <!-- Other input elements -->
    <button type="submit" class="btn btn-primary">Submit</button>
</form>

In your JavaScript file, import the corresponding function for the service. The first argument should be a CSS selector matching the form element or a parent, wrapper element.

The selector expects a single element; if multiple are matched, only the first one is used.

import { contactForm7Bus } from 'formbus';

const contactFormBus = contactForm7Bus('form#contact-form');

Or you can pass a HTMLElement directly:

const contactFormWrapper = document.querySelector('section#contact-form-section');
const contactFormBus = contactForm7Bus(contactFormWrapper);

You have to call the init method explicitly for the initialization:

contactFormBus.init();

Later on, you can call destroy if you want to remove the events attached to the form:

contactFormBus.destroy();

With multiple form elements

If you want to target multiple elements on the page, first get the elements, and then loop over them:

const forms = document.querySelectorAll('form');

forms.forEach(form => {
    const cf7FormBus = contactForm7Bus(form);

    cf7FormBus.init();
});

Supported services

Contact Form 7

Just another contact form plugin for WordPress. Simple but flexible.

import { contactForm7Bus } from 'formbus';

The REST API endpoint, if not altered, should look like this:

https://your-website.com/wp-json/contact-form-7/v1/contact-forms/<ID>/feedback
Gravity Forms

Gravity Forms is the Easiest, Most Trusted Tool to Create Advanced Forms for Your WordPress-Powered Website.

import { gravityFormsBus } from 'formbus';

The REST API endpoint, if not altered, should look like this:

https://your-website.com/wp-json/gf/v2/forms/<ID>/submissions
Your service

FormBus is extensible; if your endpoint returns field validation errors, and you can infer the submission state, you should be able to use it with your service. More about this later.

Directives

Directives are useful when you want to have what is expected. Just add one of the attributes to an element, and FormBus will do the rest.

<form action="https://your-website.com/wp-json/contact-form-7/v1/contact-forms/43/feedback"
      method="post"
      id="contact-form"
+     form-state-class>

+   <div form-state-message></div>

+   <div class="form-group" field-validation-error-class="your-name">
        <label for="name">Your Name</label>
        <input type="text" name="your-name" class="form-control" id="name">
+       <div field-validation-error-message="your-name"></div>
    </div>
    <!-- Other input elements -->
    <button type="submit" class="btn btn-primary">Submit</button>
</form>

Depending on your case, you can use only one directive or all of them:

  • field-validation-error-class
  • field-validation-error-message
  • form-state-class
  • form-state-message

For separate form states:

  • form-submission-error-class
  • form-submission-error-message
  • form-submission-success-class
  • form-submission-success-class
  • form-validation-error-class
  • form-validation-error-message

Events

With the helper functions, you get a lot of flexibility, but it's up to you to act on different states.

Events are attached to the form element.

afterFormBusResponse

const contactForm = document.querySelector('#contact-form');
const contactFormBus = contactForm7Bus(contactForm);

contactFormBus.init();

contactForm.addEventListener('afterFormBusResponse', ({ detail: response }) => {
    console.log(response);
});

This custom event is fired after the form submission when a response is returned.

The event's detail contains the raw response object. The format and the returned data that depends on the service.

Response helper functions

Because the response differs from service to service, FormBus provides a set of helper functions that you can use instead of writing logic that is bound to a specific service.

The following methods are accessible under the responseHelpers key:

  • getFieldValidationErrorMessage(responseData, fieldName)
  • getFormSubmissionErrorMessage(responseData)
  • getFormSubmissionSuccessMessage(responseData)
  • getFormValidationErrorMessage(responseData)
  • isFieldValidationError(responseData, fieldName)
  • isFormSubmissionError(responseData)
  • isFormSubmissionSuccess(responseData)
  • isFormValidationError(responseData)

Here's an example where it replaces the form element with the success message:

contactForm.addEventListener('afterFormBusResponse', ({ detail: response }) => {
    const helpers = contactFormBus.responseHelpers;

    if (!helpers.isFormSubmissionSuccess(response)) {
        alert('Something went wrong.');
        return;
    }

    const successMessage = helpers.getFormSubmissionSuccessMessage(response);

    contactFormBus.destroy();
    contactForm.innerHTML = `<p>${successMessage}</p>`;
});

beforeFormBusRequest

contactForm.addEventListener('beforeFormBusRequest', ({ detail: formData }) => {
    console.log(formData);
});

The custom event's detail contains the FormData that is sent with the request.

Configuration

You can overwrite the default configuration by passing an object as the second argument.

const yourConfig = {
    classNames: {
        fieldValidationError: '--is-error'
    }
};
const contactFormBus = contactForm7Bus('#contact-form', yourConfig);

Configuration values are merged with the defaults. If you want to overwrite a few of them, you don't have to provide the entire configuration object.

The default configuration:

const defaultConfig = {
    directives: {
        fieldValidationErrorClassNames: 'field-validation-error-class',
        fieldValidationErrorMessage: 'field-validation-error-message',
        formStateClassNames: 'form-state-class',
        formStateMessage: 'form-state-message',
        formSubmissionErrorClassNames: 'form-submission-error-class',
        formSubmissionErrorMessage: 'form-submission-error-message',
        formSubmissionSuccessClassNames: 'form-submission-success-class',
        formSubmissionSuccessMessage: 'form-submission-success-message',
        formValidationErrorClassNames: 'form-validation-error-class',
        formValidationErrorMessage: 'form-validation-error-message'
    },
    classNames: {
        fieldValidationError: 'is-error is-field-validation-error',
        formSubmissionError: 'is-error is-form-submission-error',
        formSubmissionSuccess: 'is-success is-form-submission-success',
        formValidationError: 'is-error is-form-validation-error'
    },
    request: {}
};

Customizing the directive attributes

const yourConfig = {
    directives: {
        fieldValidationErrorClassNames: 'data-field-error-class',
        fieldValidationErrorMessage: 'data-field-error-message'
    }
};
<form action="https://your-website.com/wp-json/contact-form-7/v1/contact-forms/43/feedback"
      method="post"
      id="contact-form"
      form-state-class>

    <div form-state-message></div>

-   <div class="form-group" field-validation-error-class="your-name">
+   <div class="form-group" data-field-error-class="your-name">
        <label for="name">Your Name</label>
        <input type="text" name="your-name" class="form-control" id="name">
-       <div field-validation-error-message="your-name"></div>
+       <div data-field-error-message="your-name"></div>
    </div>
    <!-- Other input elements -->
    <button type="submit" class="btn btn-primary">Submit</button>
</form>

Use your service

Instead of service functions, use the formBus that expects to receive response helpers' implementation as the second argument:

import { formBus } from 'formbus';

const contactFormBus = formBus('#contact-form', serviceResponseHelpers);

contactFormBus.init();

You are expected to return a string or a null for these functions:

  • getFieldValidationErrorMessage
  • getFormSubmissionErrorMessage
  • getFormSubmissionSuccessMessage
  • getFormValidationErrorMessage

You are expected to return a boolean for the following:

  • isFieldValidationError
  • isFormSubmissionError
  • isFormSubmissionSuccess
  • isFormValidationError
const getFieldValidationErrorMessage = (response, fieldName) => {
    return null;
};

const getFormSubmissionErrorMessage = (response) => {
    return null;
};

const getFormSubmissionSuccessMessage = (response) => {
    return null;
};

const getFormValidationErrorMessage = (response) => {
    return null;
};

const isFieldValidationError = (response, fieldName) => {
    return false;
};

const isFormSubmissionError = (response) => {
    return false;
};

const isFormSubmissionSuccess = (response) => {
    return false;
};

const isFormValidationError = (response) => {
    return false;
};

const serviceResponseHelpers = {
    getFieldValidationErrorMessage,
    getFormSubmissionErrorMessage,
    getFormSubmissionSuccessMessage,
    getFormValidationErrorMessage,
    isFieldValidationError,
    isFormSubmissionError,
    isFormSubmissionSuccess,
    isFormValidationError
};

The configuration object can be passed as the third argument.

const contactFormBus = formBus('#contact-form', serviceResponseHelpers, yourConfig);

Changelog

All notable changes to FormBus are documented in CHANGELOG.md.

Contributing

If you are using FormBus and found a bug, then you are likely the most capable of fixing it. You can contribute back the fix by submitting a pull request together with the steps to reproduce it.

Another way to help is by improving the readme.

Versions

Current Tags

  • Version
    Downloads (Last 7 Days)
    • Tag
  • 0.5.2
    0
    • latest

Version History

Package Sidebar

Install

npm i formbus

Weekly Downloads

0

Version

0.5.2

License

MIT

Unpacked Size

64.8 kB

Total Files

40

Last publish

Collaborators

  • meszarosrob