Where has basePath gone in Drupal 8?

Javascript code in Drupal 7 used drupal_add_js() to attach Javascript code to a webpage.  The Javascript code then used Drupal.settings.basePath to prepend the path to the Drupal installation.  For Drupal installed in the root directory, Drupal.settings.basePath is just the string '/' but if Drupal is installed in a subdirectory then this is necessary for the Javascript code to continue to work.  The php part is

drupal_add_js(drupal_get_path('module', 'mymodule') . '/mymodule.js');

and the Javascript part is

(function ($) {
  Drupal.behaviors.batch_jobs = {
    attach: function (context, settings) {
      ...
      $.get(Drupal.settings.basepath + 'path/to/callback', null, updatePage);

    var updatePage = function(response) {
      ...
    }
  };
})(jQuery);

The equivalent code in Drupal 8 requires an additional step and is not well documented. Start with the typical info file.

name: My Module
type: module
description: My module functionality.
package: Other
core: 8.x

The routing file will have an entry for the form and the callback for the Javascript code to retrieve the button text.

mymodule.example:
  path: 'mymodule/example'
  defaults:
    _form: '\Drupal\mymodule\Form\MyModuleExample'
    _title: 'My Module Example'
  requirements:
    _permission:  'access content'

mymodule.callback:
  path: 'mymodule/callback'
  defaults:
    _controller: '\Drupal\mymodule\Controller\MyModuleController::text'
  requirements:
    _permission: 'access content'

Note that this uses '_controller.' Since this callback returns a Response object that is correct. Some examples of routing files will have '_content' but recently this was changed so that '_controller is always used. Now the form for this example is a simple form with a button with the text "Replace me."

<?php

/**
 * @file
 * Contains \Drupal\mymodule\Form\MyModuleExample.
 */

namespace Drupal\mymodule\Form;

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

/**
 * My Module example.
 */
class MyModuleExample extends FormBase {

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

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state) {
    $form = array();

    $form['submit'] = array(
      '#type' => 'submit',
      '#value' => t('Replace me'),
    );
    $form['#attached']['library'][] = 'mymodule/mymodule';

    return $form;
  }

The form also attaches a library from the mymodule module with the library name mymodule. For Drupal 8, this extra step defines the code (Javascript and CSS) to be attached . The file mymodule.libraries.yml specifies the libraries.

mymodule:
  version: VERSION
  js:
    js/mymodule.js: {}
  dependencies:
    - core/jquery
    - core/drupal
    - core/drupal.form
    - core/drupalSettings

The Javascript file is js/mymodule.js. The drupalSettings library is also specified as a dependency. The js/mymodule.js file has the following code

(function ($, Drupal, drupalSettings) {
  Drupal.behaviors.batch_jobs = {
    attach: function (context, settings) {

      var path = 'mymodule/callback';
      alert(drupalSettings.path.baseUrl + path);
      //console.log(drupalSettings.path);
      alert('Change the button text');
      $.get(drupalSettings.path.baseUrl + path, null, updatePage);

    }
  };

  var updatePage = function(response) {
    if (response.status) {
      $('form#my-module-example input.form-submit').attr('value', response.text);
    }
  };

})(jQuery, Drupal, drupalSettings);

The first alert will show the path. If Drupal is installed in the root directory then this just adds '/' to the beginning of the path. This only becomes important when Drupal is installed in a subdirectory where the subdirectory will be prepended to the path. Drupal.settings.basePath has become drupalSettings.path.baseUrl. The line commented out with console.log can be used to output the object in Firebug or other developer tools so the contents can be examined. The remaining code is the controller src/Controller/MyModuleController.php which retrieves the text.

<?php

/**
 * @file
 * Contains \Drupal\mymodule\Controller\MyModuleController.
 */

namespace Drupal\mymodule\Controller;

use Drupal\Core\Controller\ControllerBase;
use Symfony\Component\HttpFoundation\JsonResponse;

class MyModuleController extends ControllerBase {

  /**
   * {@inheritdoc}
   */
  public function text() {
    $response = new \stdClass();
    $response->status = TRUE;
    $response->text = 'Submit this form';
    return new JsonResponse($response);
  }

}

Typically the controller would retrieve information from the database but this example simply returns the text. Now enable mymodule and navigate to mymodule/example. A form with a button appears and a Javascript popup with the path. Click okay and a second popup appears asking to change the button text. Click okay and the text will change.

Categories