0

i'm rendering a form and using an alter hook for changing the form to submit via ajax. This works like a charm. ( Drupal 8 webform with webform_ajax )

Now i want to render the form via ajax into the content. This also works.

Because the content is not there on page load i have to re-apply the drupal behaviours.

This is the thing i can't get to work.

Here's the code i use: Form.js

(function ($, Drupal) {

  'use strict';

  var $modal = $('#modal');
  var url = $('.block-system-main-block > article.node').attr('about');

  Drupal.behaviors.formInModal = {
    attach: function (context, settings) {
      $(context).find('.js-engagement-link').once('js-engagement-link').each(function () {
        var targetForm = $(this).data('target');

        $(this).click(function(){
          $.ajax({
            url: '/contact_bridge/webform/' + targetForm
          }).done(function(response) {
            $modal.find('.modal-content').first().html(response);
            $modal.foundation('open');
            Drupal.attachBehaviors($('#modal')[0], settings);
          });
        });
      });
    }
  };
})(jQuery, Drupal);

Form alter:

public function formAlter(array &$form, FormStateInterface $formState, $formId) {
  $webformSubmission = $formState->getFormObject()->getEntity();
  if ($this->isAvailable($webformSubmission->getWebform())) {
    $ajax = $this->getAjaxProperties($formId);
    $form['#prefix'] = '<div id="' . $ajax['wrapper'] . '">';
    $form['#suffix'] = '</div>';
    $form['actions']['submit']['#ajax'] = [
      'callback' => '\Drupal\webform_ajax\Controller\WebformAjaxController::ajaxSubmission',
      'wrapper' => $formId . '_wrapper',
    ]
  }
}

I tried many different calls to attachBehaviours, nothing seems to work. The alter hook is applied to the form and the ajax wrapper is there.

-- edit1 --

Here the code on the backend side for rendering the block:

<?php

namespace Drupal\contact_bridge\Controller;

use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Render\HtmlResponse;
use Drupal\Core\Render\RendererInterface;
use Drupal\Core\Url;
use Drupal\webform\Entity\Webform;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 *
 */
class ContactBridgeController extends ControllerBase {

  /**
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected $entityTypeManger;

  /**
   * @var \Drupal\Core\Render\RendererInterface
   */
  protected $renderer;

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('entity_type.manager'),
      $container->get('renderer'),
    );
  }

  /**
   * {@inheritdoc}
   */
  public function __construct(
    EntityTypeManagerInterface $entityTypeManager,
    RendererInterface $renderer
  ) {
    $this->entityTypeManger = $entityTypeManager;
    $this->renderer = $renderer;
  }

  /**
   * @param string $webformid
   * @return \Drupal\Core\Render\HtmlResponse
   */
  public function getWebformBlockHtml($webformid) {
    $webform = Webform::load($webformid);
    $renderArray = $this->entityTypeManager()->getViewBuilder('webform')->view($webform);

    $html = $this->renderer->renderPlain($renderArray);
    return HtmlResponse::create($html);
  }

}

And the routing:

contact_bridge.webform:
  path: 'contact_bridge/webform/{webformid}'
  defaults:
    _controller: '\Drupal\contact_bridge\Controller\ContactBridgeController::getWebformBlockHtml'
  requirements:
    _permission: 'access content'
    webformid: ^[a-zA-Z0-9_]+

Can somebody tell me what i'm doing wrong?

Thanks in advance.

  • Can you please also include the code that is being executed at '/contact_bridge/webform/' + targetForm? – Jaypan Apr 3 '17 at 12:50
  • Sure i edited the question above. – yobottehg Apr 3 '17 at 13:06
3

Ok, there are a few things that need to be done:

  1. Create a custom ajax command

  2. Create the JS to handle that custom command

  3. Return an AjaxResponse from getWebformBlockHtml(), that contains that custom command from step 1

  4. Ajaxify the response when your ajax is complete

You can do that as follows:

Step 1 - Create a custom ajax command

namespace Drupal\[MODULENAME]\Ajax;

use Drupal\Core\Ajax\CommandInterface;

class MODULENAMELoadFormCommand implements CommandInterface
{
  protected $form;

  public function __construct($form)
  {
    $this->form = $form;
  }

  /**
   * Implements Drupal\Core\Ajax\CommandInterface:render().
   */
  public function render()
  {
    return [
      'command' => 'MODULENAMELoadFormCommand',
      'form' => $this->form,
    ];
  }
}

Step 2 - Create the JS to handle that custom command

Add the following to your JavaScript that you're loading on page load:

Drupal.AjaxCommands.prototype.MODULENAMELoadFormCommand = function(ajax, response)
{
  $modal.find('.modal-content').first().html(response.form);
  $modal.foundation('open');
  Drupal.attachBehaviors($('#modal')[0], settings);
};

Step 3 - Return an AjaxResponse from getWebformBlockHtml() that contains that custom command from step 1

use Drupal\Core\Ajax\AjaxResponse;

public function getWebformBlockHtml($webformid) {
  $response = new Ajaxresponse();

  $webform = Webform::load($webformid);
  $renderable = $this->entityTypeManager()->getViewBuilder('webform')->view($webform);

  $rendered_form = \Drupal::service('renderer')->renderRoot($renderable);
  $response->setAttachments($renderable['#attached']);

  $response->addCommand(new MODULENAMELoadFormCommand($rendered_form));

  return $response;
}

Step 4 - Ajaxify the response when your ajax is complete

Modify your original Ajax Call to look like this:

$.ajax({
  url: '/contact_bridge/webform/' + targetForm,
  success:function(response) {
    var ajaxObject = Drupal.ajax({
      url: "",
      base: false,
      element: false,
      progress: false
    });

    // Simulate an AJAX response having arrived, and let the Ajax
    // system handle it.
    ajaxObject.success(response, "success");
  }
});
  • Thank you very much, this kinda works. the Form submits via ajax. But i get this reponse while submitting: The form has become outdated. Copy any unsaved work in the form below and then – yobottehg Apr 3 '17 at 13:51
  • I think that's likely an unrelated issue. Try using your form in a non-ajax page and see if you get the same issue. If you do, then it's a separate topic from this one. – Jaypan Apr 3 '17 at 13:56
  • I just tried it. If i just embed the form as a block on a page and submit it via ajax it works. So this has to do something with the ajax call. My first thought was the honeypot module but even disabling this module does not change the behaviour. – yobottehg Apr 3 '17 at 14:01
  • Sorry, I have no clue. This works fine when doing it with a form built through the Form API, I'm guessing it must have something to do with it being a webform. – Jaypan Apr 3 '17 at 14:12
  • 1
    I just ran into the same issue that you were having with the outdated form. I spent some time researching it, and I've updated my answer so it actually works now! – Jaypan Apr 24 '17 at 5:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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