Making Custom FAPI Element in Drupal

Vasily Grotov's picture
Posted by Vasily Grotov
FAPI - look into an abyss. I guess FAPI has become a synonym to “bread” for you, if you had already built custom forms in Drupal. But if you haven’t - don’t worry,- i It takes some time and knowledge to learn how this “weird” tool works. In fact you should learn some basics of Form API first. Drucoder Evgeny Black has wrote a thorough excursus on this topic - “Introduction to Forms API or how forms work in Drupal”.

Slider by your hands. Actually, FAPI is very flexible tool. You can build any form that comes to your mind by using this Drupal tool. There are times, when our fantasy flies high and standard form elements become insufficient for the tasks we have set. Fortunately, there are a lot of descent jQuery plugins on the web, that would help us improve usability. In this article, we’ll introduce you to a well-known library jQuery UI, which by virtue of Drupal contributors efforts, has been moved into core for Drupal 7. Thus we’ll write a custom Form API element, which allows you to integrate a cool slider into particularly any form you create.

It is never too late to mend. Let’s start with the name for our module. I chose slider_element for mine. This name will be displayed in numerous examples below. Thus, if you decide to go with your own name for the module, make sure not to just copy/paste the code given below and wonder, why is it not working :D

Telling Drupal about our module.

hook_element_info() - the “heart” of our module. API - We tell Drupal about element we want to be created by using this hook. Let's also take a look at the list of possible FAPI attributes:
  • “#input” – declares, whether element stores data or not.

  • “#element_validate” - array of validation functions.

  • “#process” - array of process functions (determine the appearance).

  • “theme” – theme-function for element and all of his “children” generation.

  • “#theme_wrappers” - element’s wrappers.

  • “#attached” - array that describes attached JS and CSS. Here we will attach core library and custom JS later on.

  • “#after_build” - array of functions for sequence call after element is built.

  • “#pre_render” - array of functions for sequence call before render in browser.

  • “#post_render” - array of functions for sequence call after render in browser.

  • "#title_display" - string describes element’s title appearance. Possible values: “before”, “after”, “invisible”, “attribute” and “none“.
You always can use your custom attributes. But you must take care of their uniqueness (best practice is to use element’s name in prefix). “#slider_value” - our slider’s value indicator.

Now Drupal knows about our element. But it’s not sure about the input. Let’s tell Drupal about it. We will describe slider’s structure (not HTML) in process function slider_process() (we had previously used it in hook_element_info()).

Building our slider with textfield (‘slider_value’) and empty div (‘slider_cont’). We will store current slider’s value in the textfield. And the div is a good container for the slider. Also we wrap both sub-element with subsidiary div with class “slider-base-cont”. This one will help us when we will get to writing JS.

Taking care of data validation:

If something dirty and very bad seeped into the textfield (we storing slider’s current value there) - we need to stop the form validation. $element[‘#slider_value’] - is our textfield, wich we have used in the process function. That’s where slider’s values will be put with the help of JS.

Now all we have to do is to relax and take a sip coffee... And write few lines of JS, of course. [=

slider.js Time to remind, that our script is in “js” subfolder (hook_element_info()). So we need to create “js” subfolder and place slider.js script in there. What it does: it looks for all slider’s containers and implements slider() method on them.
More info - Now we can get to testing:
Custom FAPI Element in Drupal

That's it. Coffee spills all over the stomach. Joyful grin is creeping across the face. Mission accomplished.