Select2: jqModal + Select2 = can’t type in
The Select2 control placed in the jqModal modal dialog doesn’t allow typing anything in. It’s unexpected, but explainable: jqModal eliminates all keypress and keydown events coming from without, i.e. coming from the controls not residing in the jqModal container. As I mentioned in the Select2: Make dropdown vertically wider, the Select2, in turn, dynamically appends the elements making up the dropdown (including the type-ahead search box) to the Body-tag, so they are literally out of jqModal dialog.
Where the contracted jqModal markup resembles the following:
<div id="myModalDialog" class="popup-6"...> <div class="pp6-header"> <h3>Some Fancy Modal Dialog</h3> <span class="close" ...></span> </div> <div class="pp6-body" ...> <select id="mySelect2" ...> <option value="">Select an option</option> <option value="Product">Product</option> <option value="Producer">Producer</option> ... </select> </div> <div class="pp6-footer"> <a href="javascript: void(0)" class="ok" ...>OK</a> <a href="javascript: void(0)" class="close" ...>Cancel</a> </div> </div>
The Select2 and modal dialog are created as follows:
$("#mySelect2").select2(); ... $("#myModalDialog").jqm({ modal: true, trigger: false, onHide: function (h) { // hash object; // w: (jQuery object) The modal element // c: (object) The modal's options object // o: (jQuery object) The overlay element // t: (DOM object) The triggering element h.o.remove(); // remove overlay h.w.hide(); // hide window }, onShow: function (hash) { hash.o.addClass("modalBackground").prependTo("body"); // add overlay // getNextDialogZIndex is my custom function, // which increments z-index counter to place each new dialog atop the preceding one if (typeof getNextDialogZIndex === "function") { var zIndex = getNextDialogZIndex(); hash.o.css("z-index", zIndex); hash.w.css("z-index", zIndex + 1); } hash.w.css("left", 0); hash.w.css("right", 0); hash.w.css("position", "fixed"); hash.w.css("margin-left", "auto"); hash.w.css("margin-right", "auto"); hash.w.fadeIn();//show(); } }); ... $("#myModalDialog").jqmShow();
Below I quote the code from jqModal.js where the keypress, keydown, mousedown events are being handled, and their bubbling is being interrupted
F = function(t){ // F: The Keep Focus Function (for modal: true dialos) // Binds or Unbinds (t) the Focus Examination Function (X) to keypresses and clicks $(document)[t]("keypress keydown mousedown",X); }, X = function(e){ // X: The Focus Examination Function (for modal: true dialogs) var modal = $(e.target).data('jqm') || $(e.target).parents('.jqm-init:first').data('jqm'), activeModal = A[A.length-1].data('jqm'); // allow bubbling if event target is within active modal dialog if(modal && modal.ID == activeModal.ID) return true; // else, trigger focusFunc (focus on first input element and halt bubbling) return $.jqm.focusFunc(activeModal); }
The code examines if the event target control or its first found parent marked with the ‘jqm-init‘ class have the associated data ‘jqm‘. If so, the event will be allowed to pass through, otherwise it will be ignored.
Based on that, we can apply a workaround to Select2 control to unlock the type-ahead search box for typing in. The solution implies to associate the proper data named ‘jqm‘ with the Select2‘s dropdown. To catch the right dropdown (we don’t want to affect other Select2 controls on the page), a unique css class has to be applied to it. Plus the dropdown has to have the ‘jqm-init‘ class to be considered and analyzed by the jqModal code (note the following fragment in the listing above:)
$(e.target).parents('.jqm-init:first')
So, the solution should look like
// create Select2 and apply proper css classes to its dropdown $("#mySelect2").select2({ dropdownCssClass: "someUniqueCssClass jqm-init" }); // capture the data associated with the jqModal container var d = $("#myModalDialog").data("jqm"); // associate the captured data with the dropdown // to mimic the residence within the jqModal dialog $(".someUniqueCssClass.jqm-init").data('jqm', d);
After that every keypress, keydown or mousedown event won’t be suppressed, but will be properly handled.