Categories

(83)
(69)
(8)
(34)
(74)
(149)

Creating modal windows (pop-ups) in Drupal 8: full tutorial

15.03.2016
Creating modal windows (pop-ups) in Drupal 8: full tutorial
Author:

Check out more tips about Drupal 8 by our experienced Drupal developers. We have already talked about Twig in Drupal 8, theming in Drupal 8, general tips on Drupal 8 development, configuration in Drupal 8. Today, we will proceed to creating modal windows. Let’s start.

Modal windows (AKA pop-ups) are incredibly convenient. They let you view/receive new and/or modified data with no need to reload the entire page. This greatly improves the website’s usability and its attractiveness for end users. Of course, we are not referring to those cases where pop-ups hamper us from viewing our favorite website, persistently trying to show an ad or offering to subscribe to a new community in social networks.

How to create and work with modal windows (pop-ups) in Drupal 8

To remember how pop-ups are created in Drupal 7, you can read the “Big Manual for creating CTools popups in Drupal 7” article. And we’ll focus our attention on Drupal 8.

Let's start with the simplest things. It’s worth reminding that standard modal windows in Drupal 8 are generated with the JQuery UI library.

In order to open some node/page in a modal window, you can add the following structure to the link to this material:

class="use-ajax” data-dialog-type="modal"

And ultimately the link will look like this:

Creating modal windows (pop-ups) in Drupal 8

Click on this link and...in most cases you will not get what you wanted...

Creating modal windows (pop-ups) in Drupal 8

Why? Because our node title includes the tags designed for micro-markup, which, in their turn, are generated by the RDF module, contained in the Drupal 8 core. Disabling the module is not a good option. So how can you solve this situation? We'll have to write the code that will cut off the unnecessary html tags only in the modal window title, because the rest of the time (e.g. during the direct viewing of the node) they are not a problem for us.

I decided to write my code on the client’s side, and after a few cups of coffee and disputes with my colleagues I got a solution presented below :)

 (function ($, Drupal, settings) {

  "use strict";

  Drupal.behaviors.Crutch = { //the name of our behavior
    attach: function (context, settings) {
      function strip_tags(input, allowed) { //the strip_tags function that cuts unnecessary tags on regular expression and returns clean text. Important! The input parameter works correctly only string data type.
        allowed = (((allowed || '') + '')
          .toLowerCase()
          .match(/<[a-z][a-z0-9]*>/g) || [])
          .join('');
        var tags = /<\/?([a-z][a-z0-9]*)\b[^>]*>/gi,
          commentsAndPhpTags = /<!--[\s\S]*?-->|<\?(?:php)?[\s\S]*?\?>/gi;
        return input.replace(commentsAndPhpTags, '')
          .replace(tags, function($0, $1) {
            return allowed.indexOf('<' + $1.toLowerCase() + '>') > -1 ? $0 : '';
          });
      }
      $(document).bind('ajaxSuccess.Crutch', function() { //run the main code only after Ajax has successfully downloaded your node
        var value = $(".ui-dialog-title"); /matching the popup title class

        if (value.length && !value.hasClass('do-once')) { //if there is no do-once class, 
          var text = strip_tags($(value).text()); //then run the strip_tags() function
          $(value).text(text);
          value.addClass('do-once');
        }
        $(this).unbind('ajaxSuccess.Crutch');
      });
    }
  };
})(jQuery, Drupal, drupalSettings);

This solution can be applied in two ways. The first way is to put it to the *.js file of your theme where you write your behaviors. The second way is to create your module and perform all these actions from it. Since later we will need our own module anyway, let's create it and call it Modal. For this and many other cases we highly recommend you to install and use Drupal console - it really saves a lot of time.

When your module is created and enabled, you can proceed to work. To start, in the modal.libraries.yml file (which you must create manually) make a custom library that will download your JS file. Here is the code with comments:

 modal: //the library name, usually starts with the module name
  version: 1.x // version
  js: // set what type of files you will be adding (e.g. css/js/etc)
    js/crutch.js: {} // the file itself
  dependencies: // setting the dependencies of your library from the main
    - core/jquery
    - core/ajax

Next, in the modal.module file, create a function that will attach your library with the script and the standard Ajax library:

 function modal_preprocess_html(&$variables) {
  $variables['page']['#attached']['library'][] = 'modal/modal';
  $variables['page']['#attached']['library'][] = 'core/drupal.ajax';
}

clean the cache and enjoy the result)).

Creating modal windows (pop-ups) in Drupal 8

By the way, you have probably noticed that I put the preprocess function module in the module file, not the theme file. And, according to the documentation, that's fine.

Speaking about styling of the standard modal windows in Drupal 8, here is a list of classes that you can use in selectors:

  • ui-dialog: The main container of the dialog window.
  • ui-dialog-titlebar: The place for the title
  • ui-dialog-title: The container where the text title itself is placed.
  • ui-dialog-titlebar-close: The button to close the window.
  • ui-dialog-content: The content zone.
  • ui-dialog-buttonpane: If you have a set of buttons, then the container for button entry is enabled)).
  • ui-dialog-buttonset: The container where all buttons themselves are placed.

We have considered the easiest option for modal window callback. But there are times when standard features are not enough. So let’s proceed to a more complex level of work.

Creating more complicated modal windows (pop-ups)

Let's create a form with a text box and a submit button in our module. In the modal window, this form should render the ID of the node whose title we enter in the text box.

Let’s begin. First, we'll create a file called modal.routing.yml, in which we set the path and parameters necessary for us to access our form. Here's the code of this file:

 modal.test_modal_form:
  path: '/modal/test-form'
  defaults:
    _form: '\Drupal\modal\Form\TestModalForm'
  requirements:
      _access: 'TRUE'

As for the file that contains the code with the form, we place it on this path: modal\src\Form\TestModalForm.php. Here's the code of this file:

 <?php

/**
 * @file
 * Contains \Drupal\modal\Form\TestModalForm.
 */

namespace Drupal\modal\Form;

use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax;
use Drupal\Core\Ajax\OpenModalDialogCommand;

/**
 * Class TestModalForm.
 *
 * @package Drupal\modal\Form
 */
class TestModalForm extends FormBase {

  /**
   * {@inheritdoc}
   */
  public function getFormId() {
    return 'test_modal_form';
  }

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state) {
    $form['#attached']['library'][] = 'core/drupal.dialog.ajax';
    $form['node_title'] = array(
      '#type' => 'textfield',
      '#title' => $this->t('Node`s title'),
    );
    $form['actions']['#type'] = 'actions';
    $form['actions']['submit'] = array(
      '#type' => 'submit',
      '#value' => $this->t('Load'),
      '#ajax' => array( // here we add Ajax callback where we will process  
        'callback' => '::open_modal',  // the data that came from the form and that we will receive as a result in the modal window
      ),
    );

    $form['#title'] = 'Load node ID';
    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {

  }
// the callback itself
  public function open_modal(&$form, FormStateInterface $form_state) {
    $node_title = $form_state->getValue('node_title');
    $query = \Drupal::entityQuery('node')
      ->condition('title', $node_title);
    $entity = $query->execute();
    $key = array_keys($entity);
    $id = !empty($key[0]) ? $key[0] : NULL;
    $response = new AjaxResponse();
    $title = 'Node ID';
    if ($id !== NULL) {
      $content = '<div class="test-popup-content"> Node ID is: ' . $id . '</div>';
      $options = array(
        'dialogClass' => 'popup-dialog-class',
        'width' => '300',
        'height' => '300',
      );
      $response->addCommand(new OpenModalDialogCommand($title, $content, $options));
    }
    else {
      $content = 'Not found record with this title <strong>' . $node_title .'</strong>';
      $response->addCommand(new OpenModalDialogCommand($title, $content));
    }
    return $response;
  }
}

Here's what the form looks like:

Creating modal windows (pop-ups) in Drupal 8

Returning to the code, let's see what we have done. To the submit form, we added Ajax callback in which we work with the data that came from the form. Let's analyze our callback code in detail.

public function open_modal(&$form, FormStateInterface $form_state)

- here we declare the function which is also the method of our class TestModalForm and to which the data from our form comes.

 $node_title = $form_state->getValue('node_title');

- here, with the help of the getValue() method, we extract the value of the node_title text field from $form_state

 $title = 'Node ID';

- the title of our would-be modal window.

 $query = \Drupal::entityQuery('node')
   ->condition('title', $node_title);
$entity = $query->execute();

- here we, using the entityQuery method with the only 'node' parameter (the entity type) and the condition with the node title, extract our id.

 $key = array_keys($entity);
$id = !empty($key[0]) ? $key[0] : NULL;

- as the result is an array whose key is the node id, we assign the non-empty value of the $key variable to the $id variable (if the node with this title already exists), otherwise the $key variable is considered NULL.

 $response = new AjaxResponse();

- here’s an interesting thing. With this line, we create a AjaxResponse() object which will enable us to send an Ajax response in the JSON format. I’ll tell you later here in more detail how to use it.

 if ($id !== NULL)

- everything is clear here ;)

 $content = '<div class="test-popup-content"> Node ID is: ' . $id . '</div>';

- here we generate a $content variable in which we will place our $id variable. This, we place the result of all our actions/queries to the $content variable.

 $options = array(
     'dialogClass' => 'popup-dialog-class',
     'width' => '300',
     'height' => '300',
);

- in this array, we set a list of parameters such as width, height, custom classes, etc.

 $response->addCommand(new OpenModalDialogCommand($title, $content, $options));

- here we add an OpenModalDialogCommand Ajax command where we add our parameters $title(the window title), $content(the window content), $options(additional parameters)

  else {
      $content = 'Not found record with this title <strong>' . $node_title .'</strong>';
      $response->addCommand(new OpenModalDialogCommand($title, $content));
    }

- in this section we set the behavior of the script when it does not find the node with this title.

 return $response

- return the Ajax response. Enter the title of some node we have created. As a result, if everything is done correctly, we will see the following picture ...

Creating modal windows (pop-ups) in Drupal 8

Instead of a conclusion

Thus, you can open some page/node using a link which has a “use-ajax” class and a data-dialog-type="modal" parameter. When it comes to forms, and when the submit result opening must be implemented in a modal window, then Ajax handler should be added to the submit. It will receive the data from the form and send the answer to the modal window. Make sure you add the core/drupal.ajax Ajax library by using the #attached parameter. Have great coding!

P.S. Here’s the archive with the module - modal.zip.

18 votes, Rating: 4.6

Read also

1

We love discussing the new features of the amazing Drupal 8 — so we are back at it again. In Drupal 8 improvements - Part 1, we talked about some of them. Now here is the promised Part 2...

2

Our Drupal developers will continue sharing Drupal 8 tips with you. Drupal 8 is gaining popularity ever since its first beta version appeared. It has brought with it many changes,...

3

We have already talked a lot about Drupal 8 release, so it’s about time to expand on the performance enhancements that have been made to it. Let’s get started!

4

After the official release, more and more Drupal developers are interested in learning about the new features of Drupal 8. So here is a chance to learn more about the Twig template...

5

In one of the recent blog posts by our developer, we offered you Drupal 8 development tips. Today, we'll...

Subscribe to our blog updates