Skip to main content

Drupal 8: Modal forms

Submitted by kaa4ever on Mon, 08/29/2016 - 17:51

Loading forms in a modal window, can often be a very good UI decision.

In Drupal 8, with the new Modal API, this is a very easy task, where only a few simple steps are required.

TL;DR

For any link, just add an 'use-ajax' class and a 'data-dialog-type' attribute with value 'modal', to make it load it's content in a modal.

A regular form

Say we have a list of items, where each item is basically just a name.
As empty, this list would look something like this:

 

An empty list

 

Clicking the “Add item” button, would redirect to a form, looking like this:

 

Adding form

 

This form is used as callback in a route definition, like this:

example.add_item:
  path: '/example/add-item'
  defaults:
    _form: '\Drupal\example\Form\AddItemForm'
    _title: 'Add Item'
  requirements:
    _permission: 'access content' 

The form definition is pretty straight forward:

namespace Drupal\example\Form;

use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;

class AddItemForm extends FormBase
{
  /**
   * {@inheritdoc}
   */
  public function getFormId()
  {
    return 'example_add_item_form';
  }

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state)
  {
    $form['name'] = [
      '#type' => 'textfield',
      '#required' => TRUE,
      '#title' => $this->t('Name'),
    ];

    $form['actions'] = [
      '#type' => 'actions',
    ];

    $form['actions']['submit'] = [
      '#type' => 'submit',
      '#button_type' => 'primary',
      '#value' => $this->t('Add item'),
    ];

    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function validateForm(array &$form, FormStateInterface $form_state)
  {
    // No validation.
  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state)
  {
    $items = \Drupal::state()->get('items') ?: [];
    $items[] = $form_state->getValue('name');
    \Drupal::state()->set('items', $items);

    drupal_set_message($this->t('Item created successfully'));
    $form_state->setRedirect('example.list_page');
  }

}

Filling out the form, the list now contains one item:

 

A list with one item

 

While this works fine, one could say, that a complete redirect to load a form with just a few fields, is a little "over the top". 
Loading this form in a modal overlay, would be a much more neat solution.

Let's do just that.

 

Modalify the form

Let's start by taking a look at the render array for the "Add Item" button.

$form['actions']['add'] = [
  '#type' => 'link',
  '#title' => $this->t('Add Item'),
  '#url' => Url::fromRoute('example.add_item'),
  '#attributes' => [
    'class' => ['button'],
  ],
];

You probably regonize the snippet as a pretty regular Drupal render array, which we all love and hate.
To make this link not redirect, but open a modal, all we need to do, is add an 'use-ajax' class and and a 'data-dialog-type' attribute with 'modal' as value. 
The updated render array looks like this:

$form['actions']['add'] = [
  '#type' => 'link',
  '#title' => $this->t('Add Item'),
  '#url' => Url::fromRoute('example.add_item'),
  '#attributes' => [
    'class' => ['button', 'use-ajax'],
    'data-dialog-type' => 'modal',
  ],
];

It's even possible to apply certain options to the modal, ie. width, height and a lot others. I havn't tested them all, but any option from the jQuery UI Dialog should work.
To add options, all you need to do, is adding a 'data-dialog-options' attribute with it's value as a JSON encoded string.

In this code, the width and height is specified:

$form['actions']['add'] = [
  '#type' => 'link',
  '#title' => $this->t('Add Item'),
  '#url' => Url::fromRoute('example.add_page'),
  '#attributes' => [
    'class' => ['button', 'use-ajax'],
    'data-dialog-type' => 'modal',
    'data-dialog-options' => Json::encode(['width' => 700, 'height' => 400]),
  ],
];

 

And that's i

Just by updating one line of code, and adding another, we can render a form in a modal.
It's easy, it's neat and it's very useful.

Thank you, Drupal 8.

Comment? Tweet me