4

I have a form with a submit button binded to an AJAX callback that opens up a modal with another AJAX form. The modal dialog opens with the form, but the AJAX submit in that modal form isn't submitting. It just flashes the AJAX spinner for a second and then disappears. I'm thinking that the form action is not correct or not set when the new form is loaded?

I get this error in my logs:
warning page not found /admin/config/custom_theme/distribution/form_action_cc611e1d?_wrapper_format=drupal_ajax

However, the form in the modal works and submits successfully via AJAX when rendered on its own (not in a modal).

The form with the submit button:

 <?php

 /**
   * Form constructor.
   *
   * @param array $form
   *   An associative array containing the structure of the form.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The current state of the form.
   *
   * @return array
   *   The form structure.
   */
  public function buildForm(array $form, FormStateInterface $form_state) {
    // Because we have many fields with the same values, we have to set
    // #tree to be able to access them.
    $form['#tree'] = TRUE;

    // Content type mapping.
    $content_types = [
      'all' => 'All',
      'article' => 'Article',
    ];
    $form['content_type'] = [
      '#type' => 'details',
      '#title' => t('Content Type Filter'),
      '#description' => t('Filter by the content type.'),
      '#collapsible' => TRUE,
      '#collapsed' => FALSE,
    ];

    // Submit button with AJAX callback.
    $form['search'] = [
      '#type' => 'submit',
      '#value' => t('Search'),
      '#ajax' => [
        'callback' => [$this, 'searchAjaxSubmit'],
        'event' => 'click',
        'progress' => array(
          'type' => 'throbber',
          'message' => 'Searching the Distribution API...',
        ),
      ],
      '#suffix' => '<div class="response-message"></div>',
    ];

    // Send to destination button.
    $form['send-destination'] = [
      '#id' => 'send_destination_btn',
      '#type' => 'submit',
      '#value' => $this->t('Send to Destinations'),
      '#attributes' => [
        'class' => ['use-ajax'],
      ],
      '#ajax' => [
        'callback' => [$this, 'sendDestinationModal'],
        'event' => 'click',
        'progress' => array(
          'type' => 'throbber',
        ),
      ],
    ];

    // Attach the library for pop-up dialogs/modals.
    $form['#attached']['library'][] = 'core/drupal.dialog.ajax';
    return $form;
  }

This is the AJAX callback for the submit button - it opens up the form in a dialog by calling dialogContents():

<?php

/**
 * AJAX callback to open the "Send to Destinations" modal.
 */
public function sendDestinationModal(array $form, FormStateInterface $form_state) {
  $response = new AjaxResponse();
  // Attach the drupal.dialog.ajax library.
  $response->setAttachments($form['#attached']);

  $content = DistributionController::dialogContents();
  // Attach the AJAX dialog library.
  $content['#attached']['library'][] = 'core/drupal.dialog.ajax';
  // Create an AJAX command that sends the content and opens up a modal
  // dialog with the specified options.
  $response = new AjaxResponse();
  $title = $this->t('Send to Destinations');
  $options = array(
    'dialogClass' => 'popup-dialog-class',
    'width' => '75%',
  );

  $response->addCommand(new OpenModalDialogCommand($title, $content, $options));
  // Return the AJAX response.
  return $response;
}  

The controller method that returns the form in the modal:

<?php

/**
 * Gets the content for the dialog.
 *
 * @param array $results
 *   The selected content from the "Search" tableselect.
 *
 * @return array
 *   The rendered markup.
 */
public static function dialogContents($results = '') {
  $form = \Drupal::formBuilder()->getForm('Drupal\my_module\Form\SendToDestinationsForm', $results);

  return [
    '#type' => 'markup',
    '#markup' => render($form),
  ];
  return $build;
}

The buildForm for the modal form:

<?php

/**
 * {@inheritdoc}
 */
public function buildForm(array $form, FormStateInterface $form_state, $options = NULL) {
  $form['#tree'] = TRUE;

  // The list of content that can be selected to send.
  $form['select_content'] = array(
    '#type' => 'checkboxes',
    '#title' => $this->t('Selected Articles'),
    '#options' => $options,
  );

  // Get the destinations from the configuration manager.
  $config = $this->config('my_module.settings');
  $data = $config->get('my_module_destinations');

  $destinations = [];
  foreach ($data as $destination) {
    $destinations[$destination['url']] = $destination['name'];
  }

  // List of destinations to chooose from.
  $form['select_destinations'] = [
    '#type' => 'checkboxes',
    '#title' => $this->t('Select Destination(s)'),
    '#options' => $destinations,
  ];

  $form['actions'] = [
    '#type' => 'actions',
  ];

  $form['actions']['send'] = [
    '#id' => 'send_destinations',
    '#type' => 'submit',
    '#value' => $this->t('Send To Destinations'),
    '#attributes' => [
      'class' => [
        'use-ajax-submit',
      ],
    ],
    '#suffix' => '<div class="response-message"></div>',
  ];

  // Attach the library for pop-up dialogs/modals.
  $form['#attached']['library'][] = 'core/drupal.dialog.ajax';

  return $form;
}

This is the callback for the submit button for the modal form:

<?php

/**
 * Send to destinations submit callback.
 */
public function submitForm(array &$form, FormStateInterface $form_state) {
  $url = 'http://www.example.com/';
  $response = DistributionController::searchDistribution($url);

  $serialized_entity = $mapper->getSerializedEntity($response);
  $endpoint = 'http://www.example.com/test/post';

  // Get the Guzzle http client.
  $client = \Drupal::httpClient();
  // Get the CSRF token for use in the POST request.
  $token = $client->get(\Drupal::request()->getSchemeAndHttpHost() . '/rest/session/token')->getBody();
  $rest_response = $client->post($endpoint, [
    'body' => $serialized_entity,
    'headers' => [
      'Content-Type' => 'application/hal+json',
      'X-CSRF-Token' => $token,
    ],
  ]);

  $form_state->setCached(FALSE);
  // Rebuild the form.
  $form_state->setRebuild();
}

Is there something I need to do when getting the modal form? Any help is appreciated!

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Browse other questions tagged or ask your own question.