Problem/Motivation

When the page contains exposed form and additional form with AJAX enabled, then only views form will work. The most frequent case is: search page with AJAX exposed form and AJAX login form. In described case login will not be possible, because form will be broken by views.

Proposed resolution

Do not build exposed form when request contain the FormBuilderInterface::AJAX_FORM_REQUEST property.

Remaining tasks

None.

User interface changes

None.

API changes

None.

Data model changes

None.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

mitsuroseba created an issue. See original summary.

mitsuroseba’s picture

mitsuroseba’s picture

Title: Disallow views to proccess custom ajax forms » Message: Symfony\Component\HttpKernel\Exception\HttpException: The specified #ajax callback is empty or not callable.
mitsuroseba’s picture

Issue tags: +Needs tests
mitsuroseba’s picture

mitsuroseba’s picture

BR0kEN’s picture

I've added a little explanation to the code and additionally fixed setters for rerender option.

BR0kEN’s picture

Title: Message: Symfony\Component\HttpKernel\Exception\HttpException: The specified #ajax callback is empty or not callable. » Views AJAX form breaks other forms
Issue summary: View changes

Status: Needs review » Needs work

The last submitted patch, 7: views-multiple_ajax_forms-2804457-7.patch, failed testing.

BR0kEN’s picture

BR0kEN’s picture

Status: Needs work » Needs review

Status: Needs review » Needs work

The last submitted patch, 10: views-multiple_ajax_forms-2804457-10.patch, failed testing.

BR0kEN’s picture

BR0kEN’s picture

Issue tags: +Dublin2016
gaydamaka’s picture

Status: Needs review » Reviewed & tested by the community

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 13: views-multiple_ajax_forms-2804457-13.patch, failed testing.

BR0kEN’s picture

Status: Needs work » Needs review
dawehner’s picture

  1. +++ b/core/modules/views/src/Plugin/views/HandlerBase.php
    @@ -810,7 +810,7 @@ public function submitTemporaryForm($form, FormStateInterface $form_state) {
    -    $form_state->get('rerender', TRUE);
    +    $form_state->set('rerender', TRUE);
         $form_state->setRebuild();
    
    +++ b/core/modules/views/src/Plugin/views/filter/FilterPluginBase.php
    @@ -1150,7 +1150,7 @@ public function addGroupForm($form, FormStateInterface $form_state) {
         $form_state->set('rerender', TRUE);
         $form_state->setRebuild();
    -    $form_state->get('force_build_group_options', TRUE);
    +    $form_state->set('force_build_group_options', TRUE);
       }
    

    Nice catches!

  2. +++ b/core/modules/views/src/Plugin/views/exposed_form/ExposedFormPluginBase.php
    @@ -110,6 +112,16 @@ public function buildOptionsForm(&$form, FormStateInterface $form_state) {
    +    if (\Drupal::request()->query->has(FormBuilderInterface::AJAX_FORM_REQUEST)) {
    +      return [];
    +    }
    

    So does that mean that you cannot use #ajax on views forms?

BR0kEN’s picture

It means that you cannot use views exposed form together with other AJAX form on the same page. In my test case I have two forms: for search and for login. Things happens because views module thinks that every request was made for it, but it's not always true.

If you want I can record a small screencast with couple Xdebug breakpoints to show what's going on.

BR0kEN’s picture

The problem still exists.

dawehner’s picture

#18.2 still exists IMHO.
Sorry but be patient, just being annoyed doesn't help :)

BR0kEN’s picture

@dawehner, I'm not annoyed :) Just trying to pay attention of others onto this ticket.

So, you are saying that if I enable AJAX in view configuration then patch will break it?

mitsuroseba’s picture

As I see now(8.2.5) we have additional check in core/lib/Drupal/Core/Form/FormBuilder.php
OLD ONE

    // After processing the form, if this is an AJAX form request, interrupt
    // form rendering and return by throwing an exception that contains the
    // processed form and form state. This exception will be caught by
    // \Drupal\Core\Form\EventSubscriber\FormAjaxSubscriber::onException() and
    // then passed through
    // \Drupal\Core\Form\FormAjaxResponseBuilderInterface::buildResponse() to
    // build a proper AJAX response.
    if ($ajax_form_request && $form_state->isProcessingInput()) {
      throw new FormAjaxException($form, $form_state);
    }

NEW ONE

    // After processing the form, if this is an AJAX form request, interrupt
    // form rendering and return by throwing an exception that contains the
    // processed form and form state. This exception will be caught by
    // \Drupal\Core\Form\EventSubscriber\FormAjaxSubscriber::onException() and
    // then passed through
    // \Drupal\Core\Form\FormAjaxResponseBuilderInterface::buildResponse() to
    // build a proper AJAX response.
    // Only do this when the form ID matches, since there is no guarantee from
    // $ajax_form_request that it's an AJAX request for this particular form.
    if ($ajax_form_request && $form_state->isProcessingInput() && $request->request->get('form_id') == $form_id) {
      throw new FormAjaxException($form, $form_state);
    }

And with this check we don't try to process AJAX submit with wrong handler.

dawehner’s picture

@mitsuroseba
This is really interesting. I ran into a similar issue recently, and I think this should really help.

Version: 8.3.x-dev » 8.4.x-dev

Drupal 8.3.0-alpha1 will be released the week of January 30, 2017, which means new developments and disruptive changes should now be targeted against the 8.4.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

BR0kEN’s picture

Issue tags: -Dublin2016 +DevDaysSeville
mitsuroseba’s picture

Status: Needs review » Closed (cannot reproduce)

Rechecked one more time and it works fine now, so close this issue.