0

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?

5
  • Does this answer your question? Custom submit handler on form loaded via entity.form_builder
    – 4uk4
    Oct 31, 2022 at 9:00
  • 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.
    – liquidcms
    Oct 31, 2022 at 13:39
  • 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.
    – 4uk4
    Oct 31, 2022 at 16:13
  • Thanks to @4uk4 i got this all working. Posted final solution above.
    – liquidcms
    Oct 31, 2022 at 23:23
  • I mean posted my solution below.
    – liquidcms
    Nov 17, 2022 at 16:54

2 Answers 2

0

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)

1
  • 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).
    – liquidcms
    Oct 31, 2022 at 3:55
0

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;
    

    }

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.