RSS

Tag Archives: updatepanel

Handling jQueryUI modal dialogs inside ASP.NET UpdatePanels

Some time ago I had some problem handling a modal jQueryUI dialog inside an UpdatePanel. When the dialog was closed an
TypeError: $(…).data(…) is null
.data( widgetFullName )._focusTabbable(); jquery-ui.js (line 10343)
error was raised into the FireBug console.

Here’s the the mystery solved, as published in http://forum.jquery.com:

the $.ui.dialog.overlayInstances global variable keeps tracks of every overlay created (maybe from multiple modal dialogs). This variable is initializated during the inclusion of the jqueryui.js file and its initial value is 0.
It’s a global, so you can access it from everywhere.

An opened modal dialog creates an overlay and increments that variable; when you close (or destroy) that dialog the variable will be decremented.

What happens if the dialog is inside an UpdatePanel?
In my test the dialog was built closed (autoOpen=false). Inside the dialog there’s a postback button: it generate a partial reload of the page and only the UpdatePanel will be rendered again.

Some event somewhere calls the .dialog(“open”) and the dialog appears (overlayInstances = 1). Now if we click that postback button, the dialog will be flushed away (not destroyed nor closed!) and the UpdatePanel will be rendered with a new copy of the dialog.
The dialog (again) starts closed but now it will be opened: the .dialog(“open”) is called and overlayInstances++ will be executed.
The $.ui.dialog.overlayInstances isn’t reinitialized, and now its value is (wrongly) 2!.

One final note:
I created another test case: the same page in HTML / javascript, with a postback emulation.
I saw that everything was running clear….until I noticed that I was replacing the UpdatePanel content with a $(“#updatePanel”).html(remoteData).
The .html() funtion is SAFE!! It destroys the inner elements and detach their events. =)
Using a document.getElementById(“updatePanel”).innerHTML = remoteData I saw the overlayInstances problem again.

The fix (updated!) :

I need to keep the balance between “open” and “close” calls to avoid the extra overlay: on every postback button I need to add a js click event that close the dialog. This will forces a _destroyOverlay event that keeps aligned the overlayInstances global value.
Here’s the code:

$('form').on("submit", function () {
  // on EVERY postback the overlay counter will be decremented.
  // if the overlay exists and will be unsafely destroyed (POSTBACK) => ok (because the destructor of the overlay has not been called)
  // if the overlay exists and will be safely destroyed (before POSTBACK) => fails! Please avoid closing dialogs in POSTBACK buttons. It is safe to set the $(settings.popupState).val('0') then postback
  // if the overlay exists and will be safely destroyed (NO POST) => ok (because the "submit" will not be raised)
  // if there's no overlay => it's ok (there's a safeness test on 0)
  if ($.ui.dialog.overlayInstances > 0)
    $.ui.dialog.overlayInstances--; // emulate the dialog closure: very rude, sir
});

This was the old fix...it has some issues:
$('input[type="submit"]', $popup)
  .add('input[type="image"]', $popup)
  .click(function () {
    $popup.dialog('close');
});

If the dialog was opened it is closed before the page load. On page load it will be (re)opened.
If the dialog was closed, it is safe to call an extra close on it.
The dialog is modal, so only inner buttons can raise a postback

 
Leave a comment

Posted by on 2013/08/20 in dev

 

Tags: , , , , ,