Score:0

Why doesn't form submit callback get called?

us flag

I have a custom page (controller) which embeds a node form. I want to submit this form via ajax but also run another submit handler which opens a modal with some of the values from that form.

My controller function is simple:

  public function createQuote() {
    $node = \Drupal\node\Entity\Node::create(['type' => 'mpep_quote']);
    $form = \Drupal::service('entity.form_builder')->getForm($node);
    $form['#attached']['library'][] = 'core/drupal.dialog.ajax';

    $form['open_modal'] = [
      '#type' => 'submit',
      '#value' => t('Open modal'),
    ];

    $form['actions']['#access'] = FALSE;

    return $form;
  }

This works fine to show the form and clicking my new submit button submits the form (non-ajax).

I have tried numerous (recommended and unsuccessful) methods of trying to get the form to submit using ajax, such as adding this to $form['open_modal']:

  '#ajax' => [
    'callback' =>  '::openQuoteModal',
    'event' => 'click',
  ],

where openQuoteModal is my additional submit function. This does not submit the form via ajax nor does it run my added submit handler.

The only way I have been able to get the form to submit via ajax is to add this to the $form['open-modal']:

'#attributes' => ['class' => ['use-ajax-submit']],

This does work to submit the form via ajax, but nothing I have done will run my added submit handler. I have tried the following:

  1. #ajax callback as shown above
  2. adding a #submit to the form submit button
  3. adding a #submit to the form itself

Is there any way to get both the from to submit via ajax as well as run a secondary form submit handler?

4uk4 avatar
cn flag
Does this answer your question? [Custom submit handler on form loaded via entity.form\_builder](https://drupal.stackexchange.com/questions/262393/custom-submit-handler-on-form-loaded-via-entity-form-builder)
liquidcms avatar
us flag
Hmm, so i can't add submit handlers after the form is built (but can add other elements to it). I tried suggestion and added the new button with my ajax callback and sure enough I now get 2 ajax throbbers showing and my callback code is run. Sadly though the form is not submitted to create the entity now. But this is closer for sure. Thanks for the tip.
4uk4 avatar
cn flag
but can add other elements to it ... not really, form elements added later miss the processing step and this can cause all sorts of problems.
liquidcms avatar
us flag
Thanks to @4uk4 i got this all working. Posted final solution above.
liquidcms avatar
us flag
I mean posted my solution below.
Score:0
us flag

Ajax forms need to have a wrapper with an id.

// Add wrapper for AJAX element.       
$form['#prefix'] = '<div id="ajaxfeedback">';       
$form['#suffix'] = '</div>'; 

And I think the callback needs to return an AJAX response.

public function openQuoteModal(array $form, FormStateInterface $form_state) {
    $response = new AjaxResponse();

    // If there are any form errors, re-display the form.
    if ($form_state->hasAnyErrors()) {
      $response->addCommand(new ReplaceCommand('#ajaxfeedback', $form));

      return $response;
    }

    $response->addCommand(new OpenModalDialogCommand("Success!", 'The modal form has been submitted.', ['width' => 500]));

    return $response;
  }

(reposted for formatting)

liquidcms avatar
us flag
Not sure about the first part but seems unlikely as the form is being submitted by ajax. The 2nd part is certainly not correct as that code is never hit (that's the issue); so nothing knows if it has an ajax response or not (it actually does though).
Score:0
us flag

From the link @4uk4 posted above I ended up simply with this:

Controller code basically the same as above except as per the link, i can't do much to the form after it is built. So it is simple this now:

  public function createQuote() {
    $node = \Drupal\node\Entity\Node::create(['type' => 'mpep_quote']);
    $form = \Drupal::service('entity.form_builder')->getForm($node);
    $form['#attached']['library'][] = 'core/drupal.dialog.ajax';

    return $form;
  }

and main part i was doing wrong was the form changes need to be done in a form alter (before it is built):

  $form['actions']['submit'] = array_merge($form['actions']['submit'], [
    '#value' => t('Get quote'),
    '#ajax' => [
      'callback' => 'openQuoteModal',
      'event' => 'click',
    ],
  ]);

This was all that was required to do 2 things:

  • submits the node form and creates the node

  • then runs the openQuoteModal function which opens a modal and that function has access to the $form values.

    function openQuoteModal($form, $form_state) {
    $response = new AjaxResponse();
    
    $values = $form_state->getValues();
    
    // Get the modal form using the form builder.
    $modal_form = print_r($values, true);
    
    // Add an AJAX command to open a modal dialog with the form as the content.
    $response->addCommand(new OpenModalDialogCommand('Your quote', $modal_form, ['width' => '1000']));
    
    return $response;
    

    }

I sit in a Tesla and translated this thread with Ai:

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.