Wednesday, February 17, 2016

Tapestry5 and the case of the disappearing bootstrap modal dialog

Tapestry5 has a pretty neat way to support JavaScript but once in a while I forget some things. Forgetting things then leads you to errors. In my case, the error was a bootstrap modal not properly displaying or disappearing immediately.

I was working on a simple but reusable modal Tapestry5 component. For some context on how to do this, go here. The important part here is the top part where you declare your JavaScript includes:

@Import(module = {"bootstrap/modal"}) 
public class ModalDialog implements ClientElement{...}

This loads the modal.js from bootstrap. Tapestry5 can do this because the framework is bootstrap aware. We then finish this up with the javascript and tml file for the component.

Thinking all was Ok, I then use this component on a page and this is where I encountered the "disappearing modal" dialog.

After debugging, I followed the bug to my layout component. Again, the important part here is where we declare the JavaScript includes:

@Import(stylesheet = {"context:datatables/css/dataTables.jqueryui.css","context:patternfly/css/patternfly.css", 
                      "context:patternfly/css/patternfly-additions.css"},
        library = {"context:patternfly/js/patternfly.js", "context:mybootstrap/js/bootstrap.min.js"})
public class Layout{...}

Apparently, bootstrap doesn't like when we double load modules. The bootstrap.min.js is a minified bootstrap and it already has the modal.js module. Then, when we load the page where we use the ModalDialog component which double loads the modal.js module.

This bug was easily fixed by removing the import annotation in my ModalDialog component.

I forgot about my JavaScript basics that invoking the script twice equals problems.

Also, this was confirmed by this StackOverflow question.