Problem/Motivation

#1824636: Do not move the cursor to the top of the page on ajax calls solved a form focus state issue where by default the focus state comes back to the form element after rebuilding part of the form after an AJAX call. This was fixed against a select element in the views module. The problem is that it works fine on select elements and checkboxes, but not on text fields and textareas. The default AJAX event for these text fields is 'blur', meaning AJAX triggers when unfocusing, for example by clicking anywhere else or pressing tab. The problem is that that by doing so, the focus comes back on these fields by default now, making it impossible to select any other form element in the form.

I don't know if this happens anywhere in Drupal out of the box, but I included a small module to reproduce the issue. Enable ajax_test and navigate to /admin/config/development/ajax-test to see the form.
A quick example of this behaviour is shown here. The top field has an AJAX callback (the sample module has it on both, resulting in a never ending back and forth focussing between the two fields). The focus always comes back to that field:
animated gif showing AJAX bug

Proposed resolution

I'm not sure what the best solution would be.

  1. I think ideally the new focus location would be passed in the AJAX callback, and placed back after rebuilding the form, but I'm not even sure if this is technically possible.
  2. If this doesn't work the least we could do is disable the auto refocus by default for text fields and textareas. This can be done by including the following property: $element['#ajax']['disable-refocus'] = TRUE
  3. suggestions?
Members fund testing for the Drupal project. Drupal Association Learn more

Comments

Danny_Joris created an issue. See original summary.

droplet’s picture

Version: 8.1.x-dev » 8.0.x-dev
droplet’s picture

Issue tags: +JavaScript
Danny_Joris’s picture

Issue summary: View changes
DuaelFr’s picture

Status: Active » Needs review
FileSize
1.39 KB

Here is a patch that disable the automatic refocus when the defined event is "blur".
I had to move the code a bit to benefit from the default event defined according to the element type.

juampynr’s picture

By looking at ajax.js I found the following logic which does the focus() call:

    // If the focus hasn't be changed by the ajax commands, try to refocus the
    // triggering element or one of its parents if that element does not exist
    // anymore.
    if (!focusChanged && this.element && !$(this.element).data('disable-refocus')) {
      var target = false;

      for (var n = elementParents.length - 1; !target && n > 0; n--) {
        target = document.querySelector('[data-drupal-selector="' + elementParents[n].getAttribute('data-drupal-selector') + '"]');
      }

      if (target) {
        $(target).trigger('focus');
      }
    }

This seems to be a non-documented feature: if you add a data attribute disable-refocus to your element, then this issue won't happen any more. I added the following to the affected form element and the issue stopped happening: '#attributes' => array('data-disable-refocus' => 'true'),.

I feel that more people will encounter this bug and waste time trying to figure it out. Why are we setting focus in the first place?

DuaelFr’s picture

You are right, I didn't document this feature when I developed it.
The best way to disable the auto-refocus is to use $element['#ajax']['disable-refocus'] = TRUE;, though.
I don't know how the FAPI documentation is generated but I suppose we should explain this a bit more there.

I still think we need to fix that particular use case because it's generating an infinite focus loop.

juampynr’s picture

Status: Needs review » Needs work

Thanks for the feedback @DuaelFr. Do you why do we have that trigger logic? I still don't understand what it is supposed to do. Sounds too opinionated to me that core focuses on the element's wrapper.

juampynr’s picture

Okay, I just finished reading the summary of #1824636: Do not move the cursor to the top of the page on ajax calls and now I get it. To be honest, I don't know what would be best to do to fix this.

DuaelFr’s picture

I think my patch fixes the issue. The blur event is really special so we should just avoid it. I suppose we should do the same with the focus event as it also could lead to an infinite loop in some cases.

juampynr’s picture

Status: Needs work » Needs review

Agree, your patch looks fine to me.

seppelM’s picture

There is another problem with TabIndex in Internet Explorer (not covered/solved by the patch in #5) and
"disable-refocus"-Inputs. (Tested in IE11 Win7 & Win10 IE13)

If you leave the field with TAB while the Ajax process is running, the focus/cursor is completely removed.
So one can't finish the form that way.

Version: 8.0.x-dev » 8.1.x-dev

Drupal 8.0.6 was released on April 6 and is the final bugfix release for the Drupal 8.0.x series. Drupal 8.0.x will not receive any further development aside from security fixes. Drupal 8.1.0-rc1 is now available and sites should prepare to update to 8.1.0.

Bug reports should be targeted against the 8.1.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.2.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.1.x-dev » 8.2.x-dev

Drupal 8.1.9 was released on September 7 and is the final bugfix release for the Drupal 8.1.x series. Drupal 8.1.x will not receive any further development aside from security fixes. Drupal 8.2.0-rc1 is now available and sites should prepare to upgrade to 8.2.0.

Bug reports should be targeted against the 8.2.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.3.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

jmccormick’s picture

I've been banging my head on this issue for a few weeks now. Adding 'disable-refocus' => true to my '#ajax' array in the field generation array fixed the problem.

droplet’s picture

Status: Needs review » Reviewed & tested by the community

I have a thought and I think it's prime time to take this action now. RBTC. #12, we need another approach for that unfortunately

DuaelFr’s picture

Issue tags: +Usability, +Ajax, +fapi ajax

Yeah #12 is totally another problem related to the replacement of some parts of the form by the AjaX callbacks.
Thanks for the review @droplet

alexpott’s picture

Status: Reviewed & tested by the community » Needs work
Issue tags: +Needs tests

Now we have javascript tests this is testable - so we don;t ever break it again.

sumanthkumarc’s picture

Adding 'disable-refocus' => true to my '#ajax' array fixed the problem.

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

Drupal 8.2.6 was released on February 1, 2017 and is the final full bugfix release for the Drupal 8.2.x series. Drupal 8.2.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.3.0 on April 5, 2017. (Drupal 8.3.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.3.x-dev branch from now on, and new development or disruptive changes should 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.

facine’s picture

Hi, here is a patch Drupal 8.3.x.

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

Drupal 8.3.6 was released on August 2, 2017 and is the final full bugfix release for the Drupal 8.3.x series. Drupal 8.3.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.4.0 on October 4, 2017. (Drupal 8.4.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.4.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.5.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.