Skip to content
GitLab
Projects Groups Snippets
  • /
  • Help
    • Help
    • Support
    • Community forum
    • Submit feedback
    • Contribute to GitLab
  • Sign in / Register
  • B bootstrap
  • Project information
    • Project information
    • Activity
    • Labels
    • Members
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributors
    • Graph
    • Compare
  • Issues 263
    • Issues 263
    • List
    • Boards
    • Service Desk
    • Milestones
  • Merge requests 114
    • Merge requests 114
  • CI/CD
    • CI/CD
    • Pipelines
    • Jobs
    • Schedules
  • Deployments
    • Deployments
    • Environments
    • Releases
  • Packages and registries
    • Packages and registries
    • Package Registry
    • Infrastructure Registry
  • Monitor
    • Monitor
    • Incidents
  • Analytics
    • Analytics
    • Value stream
    • CI/CD
    • Repository
  • Wiki
    • Wiki
  • Snippets
    • Snippets
  • Activity
  • Graph
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
Collapse sidebar
  • Bootstrap
  • bootstrap
  • Issues
  • #34055
Closed
Open
Issue created May 21, 2021 by Administrator@rootContributor

Modal event.preventDefault() for show.bs.modal: disables modals with fade class from being displayed again in V4 & V5.

Created by: RichDeBourke

When an event listener attached to a Bootstrap modal (with the fade class) for show.bs.modal returns event.preventDefault(), the modal is not displayed (the correct behavior) the first time, but it will no longer be possible to trigger the modal. The button associated with the modal cannot cause the modal to open again.

This is because the modal.js module sets the value for whether the modal is transitioning or not before it triggers the show.bs.modal event. Once displaying a modal is blocked with preventDefault(), there's no way to reset the this._isTransitioning value.

Expected behavior

The expected behavior is that each time the show.bs.modal event is triggered, the event listener can prevent the modal from being shown, but prevention will not impact future requests.

This is how the show.bs.modal event works on V3.4.1. This is also how other show events work (at least for V5 for dropdown, collapse, popover, and offcanvas, which were tested).

Starting with V4.0 and continuing through to the current V5.0.1, after a show.bs.modal listener returns event.preventDefault(), Bootstrap no longer issues an event to the listener.

Why is this happening

The Bootstrap 4 and the Bootstrap 5 documentation recommends return event.preventDefault() as the way to stop a modal from being shown:

Bootstrap 4

$('#myModal').on('show.bs.modal', function (event) {
    if (!data) {
        return event.preventDefault() // stops modal from being shown
    }
})

Bootstrap 5

var myModal = document.getElementById('myModal')

myModal.addEventListener('show.bs.modal', function (event) {
    if (!data) {
        return event.preventDefault() // stops modal from being shown
    }
})

The code in the V4 & V5 modal.js files that processes preventDefault() is in the show function:

Bootstrap 4.6.0

show(relatedTarget) {
    if (this._isShown || this._isTransitioning) {
        return
    }

    if ($(this._element).hasClass(CLASS_NAME_FADE)) {
        this._isTransitioning = true
    }

    const showEvent = $.Event(EVENT_SHOW, {
        relatedTarget
    })

    $(this._element).trigger(showEvent)

    if (this._isShown || showEvent.isDefaultPrevented()) {
        return
    }

    this._isShown = true

Bootstrap 5.0.1

show(relatedTarget) {
    if (this._isShown || this._isTransitioning) {
        return
    }

    if (this._isAnimated()) {
        this._isTransitioning = true
    }

    const showEvent = EventHandler.trigger(this._element, EVENT_SHOW, {
        relatedTarget
    })

    if (this._isShown || showEvent.defaultPrevented) {
        return
    }

    this._isShown = true

For both V4 and V5, the first thing the show function does is to check whether the modal is already being shown (this._isShown) or if the modal is in the process of being shown (this._isTransistioning).

Both V4 and V5 then immediately set the this._isTransitioning value if the modal has the fade class. The value is set before triggering the show.bs.modal event.

If the event handler returns defaultPrevented, the show function is exited, leaving the this._isTransistioning set to true.

The next time the show function is called, the this._isTransistioning value is checked, and since it's true, the show function exits, preventing the modal from being displayed.

The solution

Move setting this._isTransistioning to after evaluating the defaultPrevented value, below the this._isShown = true line, will prevent this._isTransistioning from being set to true with no way to reset the value.

Test cases

Links for V4 and V5 JS Bin test cases are listed below:

  • V4.6.0 — https://output.jsbin.com/zituxof/
  • V5.0.1 — https://output.jsbin.com/vuxuzoh/

To step through the Bootstrap code and see the issue as it happens, a breakpoint can be placed at line 103 in the V4.6.0 modal.js file or line 107 in the V5.0.1 modal.js file (the show(relatedTarget) function).

There are also test cases for V3.4.1 and V4.0.0 to show the listener working on Bootstrap 3 and not working on the first version of Bootstrap 4. A V5.0.1 version with dropdown, collapse, popopen, and offcanvas is provided to show those components working propertly.

  • V3.4.1 — https://output.jsbin.com/nanuzen/
  • V4.0.0 — https://output.jsbin.com/hayahuw/
  • V5.0.1 comparison — https://output.jsbin.com/fubixug/

Test conditions

  • Operating system and version — Microsoft Windows 10 Pro / Version 10.0.19041 Build 19041
  • Browser and version
    • Chrome — 90.0.4430.212 (Official Build) (64-bit)
    • Firefox — 88.0.1 (64-bit)

Note

The JS Bin examples would validate except for the use of autocomplete="off" for the checkbox inputs. autocomplete is not valid for checkboxes, but it is the recommended solution from MDN Web Docs to control the checkbox status when a page is refreshed.

Assignee
Assign to
Time tracking