3

I'm returning a form with #ajax functionality in an Ajax response. The form is properly loaded into the page, however it is not #ajaxified, as the drupalSettings are not being returned. In D7, we could generate the JS settings AKA Drupal.settings using the following code:

$scripts = drupal_add_js();
if (!empty($scripts['settings']))
{
    $settings = '<script type="text/javascript">jQuery.extend(Drupal.settings, ';
    $settings .= drupal_json_encode(call_user_func_array('array_merge_recursive', $scripts['settings']['data']));
    $settings .= ');</script>';
}

I'm trying to find the D8 equivalent of this code, but not having much success. At the moment I'm returning a JsonResponse from my ajax callback, but I'm thinking I probably need to return an AjaxResponse. What I can't figure out is how to pass my generated form to the AjaxResponse, in order for it to return the settings along with the HTML for the form.

2 Answers 2

3

Well, I'm answering my own question. The secret is to use BubbleableMetadata. Here is my code explaining what I did and how it happened. Here is my entire controller response that generates the JSON for the response:

 public function ajax_callback($type)
 {
    // Retrieve the form
    $form = \Drupal::service('form_builder')->getForm('Drupal\path\to\Form');

    // Render the form
    $rendered_form = render($form);

    // Get the data from BubbleMetaData
    $data = BubbleableMetadata::createFromRenderArray($form);
    // Retrieve the attachments from the $data
    $attachments = $data->getAttachments();

    // Generate the settings to be sent back with the ajax response
    if(!empty($attachments['drupalSettings']))
    {
        $settings .= '<script type="text/javascript">jQuery.extend(drupalSettings, ';
        $settings .= Json::encode($attachments['drupalSettings']);
        $settings .= ');</script>';
    }

    // Send back the rendered form along with the settings
    $response = [
        'content' => $rendered_form . $settings,
        'status' => TRUE,
        'type' => $type,
    ];

    // Return the data as a JsonResponse
    return new JsonResponse($response);
}
1

You can attach the settings to the section of the array you return in the ajax callback:

$form['section']['#attached']['drupalSettings']['mysettings'] = ...
return $form['section'];

If you use an html insert command like replace or a dialog command you can do the same for the content you use in this command.

ajax.js will reattach drupal behaviors and settings after it receives the ajax response.

5
  • I'm not trying to insert the settings, I'm trying to retrieve them to send back with my Ajax response.
    – Jaypan
    Commented Jan 26, 2017 at 13:17
  • I think the js code you are looking for is already in ajax.js, see edit.
    – 4uk4
    Commented Jan 26, 2017 at 14:01
  • Again, I'm not looking to insert the settings, I need to retrieve the entire drupalSettings from the form, to send back to the browser. I figured out how to do it, you can see my solution below.
    – Jaypan
    Commented Jan 26, 2017 at 14:15
  • But thank you for your help - sorry I just re-read both my responses and they were a little curt.
    – Jaypan
    Commented Jan 26, 2017 at 14:16
  • No problem, I try to understand why AjaxResponse is not working for you. Drupal\Core\Ajax\AjaxResponse::addCommand is also using BubbleableMetadata.
    – 4uk4
    Commented Jan 26, 2017 at 14:26

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.