16

My task is to submit a contact form via AJAX and then to show a "Thank you for submission!" message, loaded in place where the form was. So I need to ajaxify existing contact form.

I found some examples of how to validate form fields using AJAX in D8, but I can't find any example of how to implement an ajax form submission and load some content via AJAX then.

How can I implement my task? How should I alter the contact form to add the required functionality?

1
  • For those that get here with a generic form question: Webform module allows you to create a form just as you want and let the results be submitted via ajax. Commented May 14, 2018 at 9:43

3 Answers 3

35

When working with ajax in forms you have to keep in mind the following things:

  • know if you are rebuilding the whole form or only part of it and wrap the form accordingly with div element that has ID attribute that you will use in the #ajax definition on the triggering element as 'wrapper'. Use #prefix and #suffix attributes for this($form['#prefix'] = '<div id="myform-ajax-wrapper">'; $form['#suffix'] = '</div>';). Also keep in mind that if you have custom template for your form to NOT render the prefix and suffix in this case({{ form|without('#prefix', '#suffix') }}) otherwise they will get rendered twice - by your template and also by the form theme wrapper. You cannot prevent this by setting #theme_wrappers to empty array since the form template contains the actual form html element.

  • in your ajax submit handler, return the whole form or portion of it that you've wrapped and want to rebuild(return $form or return $form['myelement']). You can additionally use ajax commands instead of just returning the form structure but that is more advanced stuff.

  • store every value in form state's storage until you submit the form. Do this in the submit handler($form_state->set('somevalue', $form_state->getValue('somevalue'))) and always call $form_state->setRebuild() if you are not doing the final form submission. I prefer having custom submit handlers but having more logic in the primary submit handler is totally ok as well.

  • always use #name attribute on the button that is doing the submission and if you have only single form submit handler use $for_state->getTriggeringElement()['#name'] to detect which element has submitted the form.

  • if you are using 'trigger_as' in the #ajax definition, in case you want to submit the form with select element for example, always use the same #ajax definition like you do on the button. In my experience it is required - although not stated in the documentation.

  • using #limit_validation_errors can get very tricky sometimes and to figure out why the form is not working can take quite some time, so use it carefully(this is good for isolating form errors only on the element(s) that you are actually rebuilding so that your code does not influence other parts of the form).

  • always use buttons to submit the form and if you want to have something fancy, like select being the triggering element, use the 'trigger_as' option of the #ajax configuration and hide the real button with 'js-hide' class for good UI.

  • in the form definition, get the default values from the form state's storage if they exist or assign them into the storage if they don't. Otherwise the form won't work properly.

  • don't use $this or anything else that you don't have access to externally, otherwise it will break the ajax. always use static ajax handlers.

  • when finally submitting the form, depending on the fact that you (don't)have a custom form submission handler for the ajax, disable the form rebuilding by calling $form_state->setRebuild(FALSE).

  • you can use the :: shorthand calls in the ajax submit element($element['#ajax']['callback'] = '::ajaxFormRebuild'; and $element['#submit'] = [['::ajaxFormSubmitHandler'];).

  • the ajax callback is purely to return the rebuilt form or ajax commands. Never return altered form(ie. do not alter the form array in this callback).

7
  • Great check list, if you have problems with ajax in drupal 8! (I don't understand the first point, why NOT render the ajax wrap div?)
    – 4uk4
    Commented Feb 1, 2016 at 8:48
  • I don't remember exactly but i think it might have had something to do with #theme, #theme_wrappers and handling of #prefix and #suffix attributes in the renderer. I think that you would end up with the wrapper inside of the <form> element. This of course applies only if you are rebuilding the whole form, not just some element.
    – user21641
    Commented Feb 1, 2016 at 9:08
  • 1
    Thank you, but where can I find any simple example for AJAX submitting? Commented Feb 1, 2016 at 10:35
  • 1
    drupal.stackexchange.com/a/188227/21641
    – user21641
    Commented Feb 1, 2016 at 11:01
  • @IvanJaros, thx for the answer. Do you know how to clear form values after an ajax submission?
    – milkovsky
    Commented Nov 11, 2016 at 15:17
2

To add to this checklist, if you are displaying a form in a modal window there is a possibility that the error messages will not be displayed. As Ivan Jaros said, you have to ensure that the form has a wrapper:

$form['#prefix'] = '<div id="my-form-wrapper-id">';
$form['#suffix'] = '</div>';

You'll also need to add the following to the element that is submitting the form. In most cases it would be your submit button:

$form['submit'] = [
    '#type' => 'submit',
    '#value' => $this->t('Save Changes'),
    '#attributes' => [
        'class' => [
            'btn',
            'btn-md',
            'btn-primary',
            'use-ajax-submit'
        ]
    ],
    '#ajax' => [
        'wrapper' => 'my-form-wrapper-id',
    ]
];
2

I use the Contact ajax module. Some more details about it (from its project page):

Contact Ajax implements ajax submission for Contact form in Drupal 8.

How it works

After enable the module, each contact form will show a checkbox "Use ajax". When this checkbox is enabled the contact form will show you another option "Confirmation type" with these options:

  • Load the form: will send the form without reload the page.
  • Load from custom message: load a custom text.
  • Load from node: load a node after form submission.

This module could help you if:

  • you need to customize the confirmation message
  • you need to submit a contact form without reload the page.
  • you want load a custom text or another node after form submission.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.