A. M. Douglas

Labs: autoform.js

autoform.js is a vanilla (i.e. not jQuery) JavaScript library which looks for HTML forms in the DOM and automatically handles the submit event via AJAX.

The name is a deliberate and corny perversion of Fomalhaut, which is the brightest star in the Pisces constellation. So, quite naturally, it has absolutely nothing to do with forms, it's just a word I'm familiar with which could be adapted to include the word ‘form’.

Formalhaut started life as a pair of enormous functions to handle an XMLHttpRequest submission of a form, which originally included validation logic. It worked nicely but some parts were, for all intents and purposes, hard-coded.

It wasn't until I came to repeat the process of writing logic to submit a form by AJAX without jQuery, or any other abstraction library, that I felt a need to develop something I could reuse. This was not because I didn't value the idea, but rather because my schedule was too busy and much of my work at that time consisted of rewriting or finishing messy/broken/slow websites written by others, where too much already depended on jQuery for it to be removed (and thus I was able to just do $.ajax without a care in the world.

I've always preferred writing vanilla JavaScript, however. I grew up messing with Perl and ‘DHTML’ and so when syntactic sugar libraries came along, they merely represented time-sinks for some gains to developer-friendliness (which, being a freelancer, I didn't need, and being me, didn't want) and for losses w.r.t. performance. jQuery was of course very helpful in fast-moving projects where browser-compatibility was not a straightforward problem to solve, but that, for me, is its only use.

jQuery's simplicity has naturally given rise to a huge and scattered eco-system of ‘plugins’, many of which make sophisticated animations and complex web application UIs almost trivial to build. It wasn't jQuery that ushered in the age of the single-page application—I'm sure you can remember those awful Adobe Flash websites where you couldn't copy and paste anything and links couldn't be opened in new tabs, and so on).

However, if the JavaScript community as a whole gained something from jQuery, besides a good lesson in how to design a complex library, the community must surely have seen the value of having reusable plugins that could effectively componentise web development. Sure enough, the two JavaScript frameworks/libraries on everybody's lips these days are React and Polymer—both of which are designed to enable developers to build composable, reusable snap-ins, enabling websites which can be put together almost automatically.

While I dislike both React and Polymer for a number of reasons,* the fundamental idea of reusing solid libraries enables developers to move faster. To that end, I've been writing JavaScript libraries whenever I have been unable to find one that did what I wanted it to do, or whenever the ones available were:

  • over-engineered
  • slow
  • huge
  • obtuse
  • broken
  • all of the above

So far, I've written libs to animate DOM elements in three dimensions responding to the pointer; to display an EU-required cookie warning; to lazyload images and CSS background-images based on viewport visibility; and to trivialise the creation of tabs/tabbed sections of content. Now, to that list, I append my form auto-AJAXifier.

Unlike my other libraries, formalhaut requires no configuration (at the moment). This is largely because the library checks the DOM for forms and configures itself based on attributes specified on the form. This made sense initially, because the content-type, accept-charset, HTTP method, and the URL being targeted, are all specifiable using the valid HTML attributes: enctype="", accept-charset="", method="", and action="" respectively.

Formalhaut currently works as a blunt, everything-or-nothing drop-in. Include it at the bottom of the body, make sure your forms have the right attributes and you're done. Your form submissions will be interrupted and sent via fetch/XHR instead.

The beauty of the library is that, by using attributes like method and enctype, we can gracefully degrade to native form submit behaviour if the user doesn't have JavaScript switched on, so a bit of work on your router will enable both AJAX and native form submission handling.

So how does it work? Let's have a look at the library's anatomy. The library is exposed as a global object which, when the init() is called, finds all of the forms for a given document and adds the formalhaut submit event handler.


e.preventDefault();
var form   = ( e.target || this );
var query  =
  (function(){
    var inputs = form.querySelectorAll( settings.selector ),
        i      = inputs.length,
        j      = 0,
        str    = [];

    for( ; i > j; j++ ){
      var q = (
        !!inputs[j].getAttribute( 'name' ) && !!inputs[j].value ?
        inputs[j].getAttribute( 'name' ) + '=' + inputs[j].value :
        !1
      );

      !!q && str.push( q );
    }

    if( !str.length ){
      console.error( 'Error in constructing query: no named input' );
      return false;
    }
    else {
      return str.join( '&' );
    }
  }());

!!query && formalhaut.sendForm( query, form );

This code would be considered terse by most JS developers used to plastic-packed frameworks with easy-open, “tear here” APIs, but that’s not what I aim to create. My snippets/libraries are not intended to replace a framework in any big web app; they're designed to be drop-ins for static sites and generic marketing sites where a minimum of dynamic functionality is desirable.

It's very crude but it saves plenty of time if you're just working on simple sites for local businesses (as I often do because I prefer freelancing over working for some big corporation's advertising/content-marketing machine) and you want to achieve a nice and simple user experience without including jQuery just for $.ajax.

My plan to improve the library will involve adding the ability to ignore form attributes and to supply configuration objects instead. Forms themselves will not be grabbed as one NodeList/HTMLCollection using document.forms (though this will be the default behaviour) and instead it will be possible to initialise multiple instances of formalhaut to target different forms, or groups of forms, based on CSS selectors.

You can see view the source code here:
https://github.com/wnda/autoform/

Labels: ,

0 Comments:

Post a Comment