Drupal 8: How to Alter Forms Without Modules

Author:Texas Creative
Drupal 8: How to Alter Forms Without Modules

Sometimes when working with Drupal’s exposed forms, you might get stuck with a field type that you don’t want. Often times you can find a module to help improve the style or functionality of these forms. However, in some cases using a module will not be available and you will have to make modifications directly to the code.

If you are just getting started with Drupal, and come from a JavaScript background, this will clearly be the easiest method for you. If you are familiar with PHP and want to better understand Drupal, I encourage you to try a preprocess function!

JavaScript Method (jQuery):

For the JavaScript we’ll start with a simple select field with three options (my favorite web technologies). I like to use jQuery because it’s a bit easier to read and write than Vanilla JavaScript. A quick overview, we’ll target the select field, loop through the options, and map them each to their own <a> tags in separate divs. This allows for each link to be styled individually, auto submit the form, append URL parameters, and more.

First, we’ll start with a Select Field inside of a Form Element each with a respective ID.

Now that we’re on the same page, let’s get started initializing Drupal behaviors and jQuery. In your theme folder, you’ll need a .js file for this code to live. I called mine script.js. You can read more about Drupal behaviors here.

 

(function(Drupal, $) {
  Drupal.behaviors.HOOK = {
    attach: function(context, settings) {
    }
  };
})(Drupal, jQuery);

 

// First lets get the form by ID so we have a place to append our newly created links
  $("#TheForm").append(() => {
    // Next we will hide the original select field
    $("#SelectField").hide();
    // and create a new container div for our links to live in
    const customLinks = $('<div id="CustomLinks"></div>');

 

// Here we target the options on the select field
    const selectOptions = $(this).find("#SelectField option");
    // Now we can loop through each option and get the properties we want
    // IMPORTANT: Use the function declaration to scope the "this" keyword, not an arrow function
    selectOptions.each(function() {
      // Initialize variables for the properties we want on our new links
      let optionText = $(this).text();
      et optionVal = $(this).val();
      // Create each link with assigned properties and append to our newly created container div
      let customLink = $(
        `<div class="${optionVal}"><a href="#${optionVal}">${optionText}</a></div>`
      );
      customLinks.append(customLink);
    });
    // And last but not least return our variable
    return customLinks;
  });

 

That’s it! You’ve now mastered jQuery, and can begin styling. A real use case of this method is on a site of ours that is currently in development where we have a Location “Content Type” using the List(Text) field to determine the location’s type and are outputting the locations in a view. These links append the option’s value to the URL query and submit the form on click.

Using a Preprocess Function (PHP)

Using a Drupal preprocess function in your THEME.theme file might be a little more straight forward, but in this case we’ll turn a number input field into a select field with custom build options. This will allow us to go from a non-user-friendly keyboard input to a nice, clickable option set.

Drupal has many preprocess functions for you to use depending on your specific use case. You can learn more here. For this case, I am again outputting the form in a view, exposed to the user, so I will use “THEME_form_views_exposed_form_alter”

You’ll first need to create the optionset, which can be done through a simple function that returns an associative array, replacing THEME with the name of your theme.

 

function THEME_build_distance_options() {
  return [
    '5' => '5 miles',
    '10' => '10 miles',
    '15' => '15 miles',
    '20' => '20 miles',
    '25' => '25 miles',
    '50' => '50 miles',
  ];
}

 

With our optionset ready to go, let’s modify the input field. Within your preprocess function, you might want to start by logging or printing your form so you can track down exactly where your element’s type value is. To do so, simply uncomment the first line in the function.

 

function THEME_form_views_exposed_form_alter(&$form, $form_state, $form_id) {
  //ksm($form);
  // Turn distance text input to Dropdown selector
  $form['distance']['value']['#type'] = 'select';
  $form['distance']['value']['#multiple'] = FALSE;
  $form['distance']['value']['#empty_option'] = t('Distance');
  // Call your build options function and assign it to the new select element
  $form['distance']['value']['#options'] = txc_base_build_distance_options();
  // And use unset to remove fields not needed for our new element type
  unset($form['distance']['value']['#size']);
  unset($form['distance']['value']['#min']);
  unset($form['distance']['value']['#step']);
}

 

Hopefully now you understand the power of using jQuery and/or Drupal preprocess functions to modify any element to your exact needs, and continue building awesome websites! To see more helpful tutorials on using Drupal visit some more of our blogs here.