Drupal Up - Pal up with drupal

Drupal 8 Ajax form submit example


In this article, we will see how we may implement a simple module with an Ajax form that submits in Drupal 8. It will be as simple as two fields with a submit button, and by submitting we will just get the sum of the two fields in a markup field at the top.

Lets first create an empty module in which we will host our form. All we need to do is create an empty folder with the name of our custom module under modules/custom. 

Then we simply create a .info.yml file and an empty .module file. Check the picture how my version looks:

initial module file structure

As we know - forms in Drupal 8 are simply PHP classes that in the general case extend the FormBase class. So lets simply create a class file in our module under src/Form and call it AjaxSubmitDemo

version of the module with the form class file

Here is the full content of our class:

<?php

namespace Drupal\ajax_form_submit\Form;

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

/**
 * Our example form class
 */
class AjaxSubmitDemo extends FormBase {

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

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

    $form['message'] = [
      '#type' => 'markup',
      '#markup' => '<div class="result_message"></div>'
    ];

    $form['number_1'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Number 1'),
    ];

    $form['number_2'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Number 2'),
    ];

    $form['actions'] = [
      '#type' => 'button',
      '#value' => $this->t('Submit'),
      '#ajax' => [
        'callback' => '::setMessage',
      ],
    ];

    return $form;
  }

  /**
   *
   */
  public function setMessage(array $form, FormStateInterface $form_state) {

    $response = new AjaxResponse();
    $response->addCommand(
      new HtmlCommand(
        '.result_message',
        '<div class="my_top_message">' . t('The results is ') . 
($form_state->getValue('number_1') + $form_state->getValue('number_2')) 
. '</div>')
    );
    return $response;

   }

}


As you see - our class has a namespace that contains our custom module name. Also in the use statements, we've included some stuff that we will need later on. 

Under the method getFormId() we actually are declaring our form id. 

Our actual form body, where we may include from all of the form fields, available for us with the Forms API resides under the  buildForm() method. In our case - we just created one markup field, two text fields that we are going to be summing and one button that would trigger the sum action. All quite straightforward. 

What I want to draw your attention to is the #ajax settings for the button element. 

    $form['actions'] = [
      '#type' => 'button',
      '#value' => $this->t('Submit'),
      '#ajax' => [
        'callback' => '::setMessage',
      ],
    ];

There we are basically saying - which method should be triggered when we "trigger" this element. And button we trigger by clicking. Amen to that. 

The next interesting thing happens in the setMessage method. There we are using the AjaxResponse and the  HtmlCommand classes. As the first one, we have to return and the second one we are using to output our result. 

  public function setMessage(array $form, FormStateInterface $form_state) {

    $response = new AjaxResponse();
    $response->addCommand(
      new HtmlCommand(
        '.result_message',
        '<div class="my_top_message">The result is ' . t('The results is ') . ($form_state->getValue('number_1') + $form_state->getValue('number_2')) . '</div>')
    );
    return $response;

   }

The first parameter of the HtmlCommand instance is actually the class of our markup element that we created in our form.

That is basically our fancy ajax form. Let's create a simple route for it so that we could print it and see how it looks.
In order to do that we just create an ajax_form_submit.routing.yml file in our module with the following content:

ajax_form_submit.ajax_submit_demo:
  path: 'ajax-form-submit'
  defaults:
    _form:  '\Drupal\ajax_form_submit\Form\AjaxSubmitDemo'
    _title: 'Ajax Submit Form'
  requirements:
    _permission: 'access content'

And that's it ... if we activate our module from the Extend tab ("Ajax Form Submit example" is the name of our module) and go to the path /ajax-form-submit in our Drupal instance - we should see the following form:

our ajax submit form in action

and as we input some numbers and submit - we should get the result in the previously empty markup field at the top. And all of this will happen without refreshing the page. 

The full code of the module you may find on Drupal Up's git hub page here.

Thanks for reading and I hope you enjoyed it.

PS: I know you are smart and you will try to input also chars in some of the fields but the bad news is that it will not break in the most cases