Score:2

Custom Submit Callback only triggering when Form is Valid when in Dialog

cg flag

I'm trying to create a node in a dialog with the following link:

Enter the title of a registration form or <a class="use-ajax" 
    data-dialog-options="{&quot;width&quot;:800}" 
    data-dialog-type="modal" 
    href="/node/add/mycontenttype?enableAjaxSubmit=true">
    create a new registration form.
</a>

The callback _mymodule_close_dialog() runs perfectly when there are no validation errors. But when there is an error (e.g. the title is empty), JS just outputs an error Uncaught TypeError: this.url is undefined.

I can get rid of the JS error by preventing the form actions from becoming model buttons, but then the form just silently fails.

How can I show a form's error messages when creating a node in a dialog?

The callback:

/**
 * Implements hook_form_BASE_FORM_ID_alter() for \Drupal\node\NodeForm.
 */
function mymodule_form_node_mycontenttype_form_alter(&$form, FormStateInterface $form_state) {
    $enableAjaxSubmit = \Drupal::request()->query->get('enableAjaxSubmit');
    if (!empty($enableAjaxSubmit) && $enableAjaxSubmit === 'true') {    
      $form['#attached']['library'][] = 'core/drupal.dialog.ajax';
      $form['#attached']['library'][] = 'core/jquery.form';

      $form['actions']['submit']['#attributes']['class'][] = 'use-ajax-submit';
      $form['actions']['submit']['#submit'][] = '_mymodule_close_dialog';
    }
}

use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\CloseModalDialogCommand;
use Drupal\Core\Ajax\PrependCommand;
use Drupal\Core\Ajax\AlertCommand;

function _mymodule_close_dialog(array &$form, FormStateInterface $form_state) {
  $response = new AjaxResponse();

  // if (!$form_state->getErrors()) {
    $response->addCommand(new CloseModalDialogCommand());
  // }

  $messages = ['#type' => 'status_messages'];
  $response->addCommand(new PrependCommand('.some-wrapper', $messages));

  $form_state->setResponse($response);
}

I followed:

Update

Changed:

$form['actions']['submit']['#submit'][] = '_mymodule_close_dialog';

To:

$form['actions']['submit']['#ajax']['callback'] = '_mymodule_close_dialog'; // Rename function to remove `_`
$form['actions']['submit']['#ajax']['url'] = \Drupal\Core\Url::fromRoute('node.add', ['node_type' => $contentType]);
$form['actions']['submit']['#ajax']['options'] = [
  'query' => [
    \Drupal\Core\Form\FormBuilderInterface::AJAX_FORM_REQUEST => TRUE,
  ],
];

But getting a PHP error:

Symfony\Component\HttpKernel\Exception\HttpException: The specified #ajax callback is empty or not callable. in Drupal\Core\Form\FormAjaxResponseBuilder->buildResponse()

When I debug($triggering_element) in the FormAjaxResponseBuilder file, the submit element did not have an #ajax key or the use-ajax-submit class. Thus, the triggering element is not ultimately altered.

Any ideas?

Score:0
ua flag

and a bit of: https://www.drupal.org/project/drupal/issues/2934463#comment-13180158

You missed adding this part to your alter, which should fix your url undefined problem.

$form['actions']['submit']['#ajax']['url'] = \Drupal\Core\Url::fromRoute('node.add');
$form['actions']['submit']['#ajax']['options'] = [
  'query' => [
    Drupal\Core\Form\FormBuilderInterface::AJAX_FORM_REQUEST => TRUE,
  ],
];
Chris Happy avatar
cg flag
I tried adding the code below `$form['actions']['submit']['#submit'][] = '_mymodule_close_dialog';` but then it stopped saving. Isn't the above code for opening the `node.add` form (and not for when saving the node form)? Or am I not understanding something?
Chris Happy avatar
cg flag
I added an update with your solution. Unfortunately, Drupal is not using the altered element with the `#ajax` key.
mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.