Javascript

How to resolve CSRF token issue in headless/decoupled application ?

Whenever we send a request to Drupal website from our embedded JS application, we have to send a CSRF token with request otherwise it is seen as request forgery issue. You can provide CSRF token to your JS application in the following way:

/**
 * Implements hook_page_attachments().
 */
function example_module_page_attachments(array &$attachments) {
  $attachments['#attached'] = [
    'drupalSettings' => [
      'csrf' => \Drupal::csrfToken()->get(CsrfRequestHeaderAccessCheck::TOKEN_KEY),
    ],
  ];
}

And in your JS application CSRF token can be accessed from drupalSettings object. Make sure this token is added to every request to avoid X-CSRF token not found issues.

How to attach library using hook_preprocess_page?

Hook preprocess can be used to attach libraries on any page in Drupal 8 based on any condition. Developers can also add drupalSettings variable. Here is the code snippet:

/**
 * Hook_preprocess_page().
 */
function example_preprocess_page(&$variables) {

  $variables['#attached']['library'][] = 'example_module/example_library';

  $variables['#attached']['drupalSettings']['siteBaseUrl'] = 'example.com';

}

 

How to attach jQuery in Drupal 8 Controller

jQuery file can be added to the controller in the following way:

In the controller, file make sure that library defined in libraries.yml is returned along with the markup,

return [
      '#type' => 'markup',
      '#markup' => '<div id="my_js_application"></div>',
      '#attached' => ['library' => ['example_module/example_library']]
    ];

In the libraries.yml, the example_library has to be defined.

example_library:
  version: 1.x
  js:
    js/myapp.js: {}

dependencies:
    - core/jquery

 

Now in myapp.js use the following syntax :

(function ($, Drupal) {

}(jQuery, Drupal));

 

How to handle form submission using AJAX in Drupal 8

Here is the buildForm function for creating an AJAX form.

  public function buildForm(array $form, FormStateInterface $form_state) {
  
    $form = [];
    $form['email'] = [
      '#type' => 'textfield', 
      '#attributes' => ['placeholder'=>'Enter your Email ID'],
      '#description' => 'Submit your email address to recieve updates',
      '#size' => 100,
      '#maxlength' => 150,
      '#required' => TRUE,  
    ];

    $form['submit_button'] = [
      '#type' => 'submit',
      '#name' => 'submit-email',
      '#value' => '>',
      '#ajax' => [
        'callback' => '::processEmail',
        'wrapper' => 'thanks-message',
        'effect' => 'fade',
        'event' => 'click',
        'progress' => [
          'type' => 'throbber',
          'message' => $this->t('Processing ...'),
        ],
      ],
    ];

    $form['thanks'] = [
     '#type' => '#markup',
     '#markup'=> '',
     '#prefix' => '<div id="thanks-message">',
     '#suffix' => '</div>'
    ];

    $form['error'] = [
     '#type' => '#markup',
     '#markup'=> '',
     '#prefix' => '<div id="error-message">',
     '#suffix' => '</div>'
   ];

    return $form;
  }

And this the code for callback function.

  public function processEmail (array &$form, FormStateInterface $form_state) {
    $form['#cache'] = ['max-age' => 0];
    $email = $form_state->getValue('email');
    $renderer = \Drupal::service('renderer');
    $response = new AjaxResponse();

    if (!(\Drupal::service('email.validator')->isValid($email))) {
      $elem = [
        '#type' => 'markup',
        '#markup'=> 'Please provide correct Email ID',
        '#prefix' => '<div id="error-message">',
        '#suffix' => '</div>'
      ];
      $response->addCommand(new InsertCommand('#error-message', $renderer->render($elem)));
      return $response;
    }
    else {
      $element = [
        '#type' => 'markup',
        '#markup'=> 'Thank you! Please check your email for confirmation message.',
        '#prefix' => '<div id="thanks-message">',
        '#suffix' => '</div>'
      ];

      $error = [
        '#type' => 'markup',
        '#markup'=> '',
        '#prefix' => '<div id="error-message">',
        '#suffix' => '</div>'
      ];

      //$elma used as an empty variable to hide unwanted element.s

      $response->addCommand(new ReplaceCommand('#thanks-message', $renderer->render($element)));
      $response->addCommand(new ReplaceCommand('#edit-submit-button', $renderer->render($elema)));
      $response->addCommand(new ReplaceCommand('#edit-email--description', $renderer->render($elema)));
      $response->addCommand(new ReplaceCommand('#edit-email', $renderer->render($elema)));
      $response->addCommand(new RemoveCommand('#error-message'));
      return $response;
    }
  }

How to handle form submission using JS in Drupal 7

In Drupal 7 you use behaviors to handle the form submission. It can be achieved in following way.

  $form = array();
  $form['sample_value'] = array(
    '#type' => 'textfield',
    '#title' => 'Sample Value',
    '#size' => 20,
    '#maxlength' => 150,
    '#required' => TRUE,
  );

 //Make sure you set Drupal form submission to be false.

  $form['#executes_submit_callback'] = FALSE;

  $form['submit_button'] = array(
    '#type' => 'submit',
    '#value' => t('Submit'),
  );

 //Attach the JS file to form.

$form['#attached']['js'][] = drupal_get_path('module', 'custom_module') . '/js/custom.js';

Now in your JS file, you can access the values in following ways 

/**
 * @file Javascript behaviors for the Custom module.
 */

(function ($) {
  // Make sure our objects are defined.
  Drupal.CustomForm = Drupal.CustomForm || {};

  Drupal.CustomForm.compute = function(form) {
     //You can perform any kind of operation from value variable. 

     value = form.sample_value;
  }

  Drupal.behaviors.custom = {
    attach: function (context, settings) {

      $("#edit-submit-button", context).click(function(event) {
        Drupal.CustomForm.compute(this.form);
        return false;
      });
    }
  };
})(jQuery);