Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

touch device (e.g. iOS) dropdown backdrop is removed incorrectly #16516

Closed
gwynjudd opened this issue May 20, 2015 · 8 comments
Closed

touch device (e.g. iOS) dropdown backdrop is removed incorrectly #16516

gwynjudd opened this issue May 20, 2015 · 8 comments
Labels

Comments

@gwynjudd
Copy link

This issue can be seen in this fiddle (http://jsfiddle.net/rfyt2fr3/1/) on an iOS touch device (probably other touch devices as well):

  1. click on the dropdown to show it
  2. verify using the web inspector that the dropdown backdrop has been added
  3. click anywhere in the page
  4. note that the dropdown backdrop is removed, but the dropdown didn't close due to the js event handler

On touch devices, the bootstrap plugin adds a dropdown:

https://github.com/twbs/bootstrap/blob/master/js/dropdown.js#L69

      if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) {
        // if mobile we use a backdrop because click events don't delegate
        $(document.createElement('div'))
          .addClass('dropdown-backdrop')
          .insertAfter($(this))
          .on('click', clearMenus)
      }

It's evident that this backdrop is meant to compensate for the known issue of click events not propagatingdelegating, otherwise the clearMenus doesn't run when you click anywhere:

https://github.com/twbs/bootstrap/blob/master/js/dropdown.js#L158

  $(document)
    .on('click.bs.dropdown.data-api', clearMenus)

The code that removes the backdrop does so, even if the hide.bs.dropdown event handler prevented the close.

https://github.com/twbs/bootstrap/blob/master/js/dropdown.js#L37

  function clearMenus(e) {
    if (e && e.which === 3) return
    $(backdrop).remove()
@gwynjudd
Copy link
Author

I think the backdrop should be removed in clearMenus after the hide.bs.dropdown event has completed. It should only be removed from the parent element (this is a different issue I guess, but it helps with nested dropdowns):

  function clearMenus(e) {
    if (e && e.which === 3) return
    $(toggle).each(function () {
...
      $parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))

      if (e.isDefaultPrevented()) return

      $parent.find(backdrop).remove()

      $this.attr('aria-expanded', 'false')
      $parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
    })
  }

@cvrebert cvrebert added the js label May 20, 2015
@cvrebert
Copy link
Collaborator

If we apply one of the workarounds from https://developer.mozilla.org/en-US/docs/Web/Events/click#Safari_Mobile , it's possible that the backdrop might become unnecessary.

@kkirsche
Copy link
Contributor

@cvrebert does twbs have a preference which workaround is implemented?

@cvrebert
Copy link
Collaborator

There hasn't been sufficient discussion around it yet to form a preference.
[Edit: After more testing, it turns out that the workarounds mentioned in my previous comment aren't viable due to https://bugs.webkit.org/show_bug.cgi?id=151933 ]

@cvrebert cvrebert added the v3 label Aug 19, 2015
@holtkamp
Copy link

I encountered this issue with the dropdown-backdrop element sometimes NOT being removed properly on iOS devices when using quite a few dropdown elements on a single page (around 60, we use it in an e-commerce system to have the user select a specific product option).

How to reproduce

  • open dropdown-menu by clicking button with a data-toggle="dropdown" attribute
  • select a list item from the dropdown-menu
    • note we use <li><a href="javascript:void(null);">item X</a></li> elements
  • see the dropdown-menu close automatically

Results
After about 5 to 10 times repeating these steps, it made the browser tab in both physical and simulated iOS devices freeze, emitting lots of messages in the system log:

Nov 30 17:56:45 Mennos-MacBook-Pro assertiond[6895]: assertion failed: 15B42 13B137: assertiond + 12188 [93FFE0B6-5C27-387F-B32A-6EE378BBB22A]: 0x1
Nov 30 17:57:15 --- last message repeated 45 times ---
Nov 30 17:57:15 Mennos-MacBook-Pro assertiond[6895]: assertion failed: 15B42 13B137: assertiond + 12188 [93FFE0B6-5C27-387F-B32A-6EE378BBB22A]: 0x1
Nov 30 17:57:45 --- last message repeated 89 times ---
Nov 30 17:57:45 Mennos-MacBook-Pro assertiond[6895]: assertion failed: 15B42 13B137: assertiond + 12188 [93FFE0B6-5C27-387F-B32A-6EE378BBB22A]: 0x1
Nov 30 17:57:45 Mennos-MacBook-Pro assertiond[6895]: assertion failed: 15B42 13B137: assertiond + 12188 [93FFE0B6-5C27-387F-B32A-6EE378BBB22A]: 0x1
Nov 30 17:58:15 --- last message repeated 22 times ---

Possible cause
This is possibly caused by the clearMenus() function which is executed over all dropdown-menu's on a page which might be a bit too much for iOS?

Temporary workaround
To prevent this, we manually remove the .dropdown-backdrop elements ASAP after it has been created:

$(document).on('show.bs.dropdown', function(event) {
    $('.dropdown-backdrop').off().remove();
});

I am aware that this way we do not follow the best practices of having a dropdown-menu close "when clicking elsewhere on a page", but this is better than a crashing browser tab. In this case the assertions in the system log still fail, but a lot less and the tab does not freeze anymore.

Nov 30 20:26:56 --- last message repeated 1 time ---
Nov 30 20:26:56 Mennos-MacBook-Pro com.apple.WebKit.Networking[7735]:  SecTrustEvaluate  [leaf AnchorTrusted SSLHostname ValidLeaf ValidRoot]
Nov 30 20:27:37 Mennos-MacBook-Pro assertiond[7694]: assertion failed: 15B42 13B137: assertiond + 12188 [93FFE0B6-5C27-387F-B32A-6EE378BBB22A]: 0x1
Nov 30 20:28:07 --- last message repeated 16 times ---
Nov 30 20:28:49 Mennos-MacBook-Pro assertiond[7694]: assertion failed: 15B42 13B137: assertiond + 12188 [93FFE0B6-5C27-387F-B32A-6EE378BBB22A]: 0x1
Nov 30 20:28:49 Mennos-MacBook-Pro assertiond[7694]: assertion failed: 15B42 13B137: assertiond + 12188 [93FFE0B6-5C27-387F-B32A-6EE378BBB22A]: 0x1
Nov 30 20:29:08 --- last message repeated 28 times ---
Nov 30 20:29:08 Mennos-MacBook-Pro routined[7678]: CoreLocation: Error occurred while trying to retrieve motion state update: CMErrorDomain Code:104
Nov 30 20:29:19 Mennos-MacBook-Pro assertiond[7694]: assertion failed: 15B42 13B137: assertiond + 12188 [93FFE0B6-5C27-387F-B32A-6EE378BBB22A]: 0x1

Suggestions for a more elegant approach are welcome. Just reporting this to make this issue better findable and hopefully some day have Bootstrap itself incorporate a way to improve stability on iOS devices.

@holtkamp
Copy link

Just wondering whether this issue is on the radar for version 4?

@cvrebert
Copy link
Collaborator

@holtkamp Your problem is fairly different from this issue. Please open a new issue.

@mdo
Copy link
Member

mdo commented Sep 5, 2016

Bootstrap 3 is no longer being officially developed or supported.

All work has moved onto our next major release, v4. As such, this issue or pull request is being closed as a "won't fix." For additional help and support, we recommend utilizing our community resources. Thanks for your understanding, and see you on the other side of v4!

<3,
@mdo and team

@mdo mdo closed this as completed Sep 5, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

5 participants