Search code examples
aurelia

Hiding bootstrap modal with plain javascript in typescript


I am using Aurelia with bootstrap to show the modal to ask for confirmation to clear form details. I have created plunker link for this. How can I hide the bootstrap modal without using JQuery that bootstrap provides to trigger an event to close the modal? I tried below to hide the modal, which works. But breaks the modal when you want to show it again.

document.getElementById("confirmationRequired").style.display = 'none';

When I try to click on clear btn, I get below error.

enter image description here


Solution

  • I understand (and share) your preference to try and avoid JQuery where possible, but when you're working with a JQuery component that ship has kind of sailed already.. :-)

    To answer your question (and demonstrate why it's hard to avoid JQuery when working with JQuery), here are 2 ways to hide it with "plain JS":

    1. Copy the code from bootstrap's Modal.hide():

    As you can see it does quite a few more things than just applying the hide style. Which is why that doesn't work.

    if (event) {
      event.preventDefault()
    }
    
    if (this._isTransitioning || !this._isShown) {
      return
    }
    
    const hideEvent = $.Event(Event.HIDE)
    
    $(this._element).trigger(hideEvent)
    
    if (!this._isShown || hideEvent.isDefaultPrevented()) {
      return
    }
    
    this._isShown = false
    const transition = $(this._element).hasClass(ClassName.FADE)
    
    if (transition) {
      this._isTransitioning = true
    }
    
    this._setEscapeEvent()
    this._setResizeEvent()
    
    $(document).off(Event.FOCUSIN)
    
    $(this._element).removeClass(ClassName.SHOW)
    
    $(this._element).off(Event.CLICK_DISMISS)
    $(this._dialog).off(Event.MOUSEDOWN_DISMISS)
    
    
    if (transition) {
      const transitionDuration  = Util.getTransitionDurationFromElement(this._element)
    
      $(this._element)
        .one(Util.TRANSITION_END, (event) => this._hideModal(event))
        .emulateTransitionEnd(transitionDuration)
    } else {
      this._hideModal()
    }

    I have tried similar things before and typically ended up tossing out an evening of work (figuring out and tying together all the dependencies) after concluding that I should just let the library handle it.

    That's not to say it's a total waste of time. Doing this helps you better understand how these libraries work under the hood, and ultimately saves time in the long run because the API will have fewer surprises for you.

    2. Manually invoke Modal.hide()

    This involves finding the correct jQuery object on an element, getting the object instance you need and then invoking the appropriate method on it. A quick-n-dirty way to do this:

    const el = document.getElementById("confirmationRequired");
    const modal = Object.getOwnPropertyNames(el)
        .filter(n => n.startsWith("jQuery"))
        .map(n => e[n]["bs.modal"])
        .find(j => j !== undefined);
    
    modal.hide();
    

    Or..

    I'd just use jQuery to do the same thing but with less code and more reliably.

    As jesse already pointed out, aurelia-dialog is the way to go if you want to avoid JQuery. There is a learning curve involved but it's a very neat library once you get the hang of it.

    One might argue: why not just hand-roll your own modal logic using only the CSS from bootstrap to style the dialog? A modal is nothing but two simple parts:

    • A fixed screen-filling element with a shade and positive z-index that makes the rest of the app unclickable while the modal is active. Simply show/hide it with CSS.

    • A plain form element, fixed and centered, with a higher z-index than the screen-filler. You could make this a custom element and to keep it really simple, let it communicate via the EventAggregator so you don't need to do any sorcery with tightly coupled bindings.

    Add a few event handlers like esc and clicking outside the modal as alternatives to close it, and you're golden.