Introduction
Popping up a dialog window is a very common scenario in web development, especially
in a parent-child kind of UI setup. Most of the times it might contain mostly static
content and the dynamic elements in it will be a few text changes. There are use-cases
where a jQuery dialog window should open up very dynamic content (including elements
rendered) based on certain criteria selected in the parent page.
In the first part of this article, I will demonstrate how to implement a jQuery
dialog window (modal or normal) that can contain truly dynamic content, in which
the contents are loaded from a totally different aspx/html page. In the second part
of the article, I will show you how to do a postback from a jQuery dialog window
such that the dialog window does not close automatically (which normally is the
case) once the postback is over. Not only that, I will also show you updated content
in the jQuery dialog as a result of the postback.
Background
Sometime back we had a requirement to popup a Dialog window with truly dynamic content.
Though initially it was thought to be done using native IE modal popups, as it was
easy to do it, we later decided to develop the same using jQuery UI Dialog framework.
Technologies and tools used:
- Visual Studio 2010 and C# to develop the samples.
- jQuery js files from the version 1.7.1
- jQuery UI js files from the version 1.8.17
Using the Code
For the sake of simplicity of the demo of the concept, I have used a very simple
use case scenario. The parent page consists of 2 text boxes and a button. The user
can enter the number of rows and columns in the textboxes. When the user clicks
on the button, the jQuery dialog opens up with a table with that many rows and columns
specified by the user.
The point here is that, based on the inputs from the user we can load a modal window
with dynamic content like generating a table on the fly from the server side. Remember
that since the table is rendered from the server side, it gives the user access
to all server side data – session data, .NET cache data, Database server data, remote
service data – you name it. The user can build an UI layout of his choice using
data sitting in a remote place into a jQuery modal Dialog window!
So enough of all the lecture, let’s see some code!
Loading Contents of an ASPX Page into a jQuery Dialog Window
First I will start with showing you how to load a dialog window with some dynamic
content.
$("#LoadDialogButton").off("click");
$(document).on("click", "#LoadDialogButton", function () {
var url = "DialogContentPage.aspx";
var divId = " #MainContentDiv";
var q1 = "?inp1=" + $("#Input1").val();
var q2 = "&inp2=" + $("#Input2").val();
url = url + q1 + q2 + divId; //url in the form 'DialogContentPage.aspx?inp1=xx&inp2=yy #MainContentDiv'
$('<div id=DialogDiv>').dialog("destroy");
$('<div id=DialogDiv>').dialog({
dialogClass: 'DynamicDialogStyle',
modal: true,
open: function () {
$(this).load(url);
},
close: function (e) {
$(this).empty();
$(this).dialog('destroy');
},
height: 350,
width: 540,
title: 'Dynamic Dialog'
});
});
If you look at the code above, it is typical jQuery UI syntax of loading a jQuery
modal dialog. But if you look at the ‘open’ attribute in it, it makes a request
to a URL. The URL is built in the format:
DialogContentPage.aspx?inp1=xx&inp2=yy #MainContentDiv
What it does over here is that it makes a request to this aspx page with the parent
page inputs (rows & columns) as query strings. The server generated the table
using the inputs and renders back the generated html. The generated HTML contains
a div with the id "MainContentDiv
". Everything that is generated
at the server is within this div. The contents of this div are simply loaded into
the jQuery modal window.
Let’s see the code in the parent aspx page:
<asp:UpdatePanel ID="UpdatePanel" runat="server">
<ContentTemplate>
<div>
<label for="Input1">
Rows
<input type="text" id="Input1" value="1"/>
</label>
<label for="Input2">
Columns
<input type="text" id="Input2" value="2"/>
</label>
<br />
<br />
<input type="button" id="LoadDialogButton" value="Open Dialog" class="ButtonStyle" />
<asp:Button ID="ServerButton" Text = "Server Dummy Button" runat="server" OnClick="DoSomethingOnServer"/>
</div>
</ContentTemplate>
</asp:UpdatePanel>
As you can see, I have put everything under an UpdatePanel and it has a dummy server
side button. This is not actually required for this demo to work, but I have put
the whole jQuery Dialog Window loading button (button with id LoadDialogButton)
under this to show you a point.
If you have noticed the way I have bound the click event of the button ‘LoadDialogButton
’,
I have used the syntax:
$(document).on("click", "#LoadDialogButton", function () {
instead of the most commonly used:
$("#LoadDialogButton").click(function () {
The 2nd syntax would have worked perfectly well in this demo if I haven’t used the
UpdatePanel. But there can be situation where you will use the UpdatePanel in a
real scenario, but also want the jQuery events to work.
The asp:UpdatePanel replaces the original content with the results from the server,
and what it means that all the previously hooked jQuery events using the jQuery
‘click’ syntax will not work anymore – You can try this out. This is where the jQuery.on
syntax of binding a click event helps you.
As of jQuery 1.7, the .on()
method is the preferred method for attaching
event handlers to a document. For earlier versions, the .bind()
method
(‘Click syntax’) is used for attaching an event handler directly to elements. Handlers
are attached to the currently selected elements in the jQuery object, so those elements
must exist at the point the call to .bind()
occurs. (Source)
Now on click of the ‘Open Dialog’ button, it opens up a jQuery Dialog with dynamically
generated table as shown below:
I will come to details of what happens when you click on the ‘Evaluate’ button in
the last section of this article.
Oh, I almost forgot, you need to do one more thing for this example to work correctly.
As you can in this example that the entire contents of the jQuery Modal window is
loaded from DialogContentPage.aspx. The problem here is that if you close the modal
window and open it again, after changing some inputs, say number of rows
or columns changed, you will see that it has opened with a layout which was previously
opened!
I think you have guessed what has happened, yes, the browser has cached the previous
page and hence opened up that. You can easily avoid this by adding some more code
in the Page_Init of the DialogContentPage.aspx. Let's see that
protected void Page_Init(object sender, EventArgs e)
{
Response.Cache.SetCacheability(System.Web.HttpCacheability.NoCache);
Response.Cache.SetNoStore();
}
What it does is, it adds the following response headers, and it makes sure that
this particular page is never cached (atleast on IE and Firefox)
Cache-Control: no-cache, no-store
Pragma: no-cache
Expires:-1
I have captured the same in Fiddler, you can see that below:
Loading a div with server side components into a jQuery Dialog Window
Another scenario where we usually encounter is when we will have to load a jQuery
Dialog window with server side contents. In this example, I have a div ‘LocalDialogModal
’
which has a asp:Label, asp:TextBox, and an asp:Button. The asp:button has a server
side method "SaveEmployeeBtn_Click
".
I am going to show you how to load this div into a jQuery Modal Dialog and still
be able to call the server side method on the click of the asp:button
Have a look at the div element placed within the form tag of the parent page:
<div id='LocalDialogModal' style="display: none">
<span style="font-style: italic; font-size: x-small; color: Gray;">Note: This is a
jQuery modal dialog which does not have dynamic content but this content has server
side elements, and is defined in the parent page
<br />
<asp:Label ID="lblNewName" runat="server" AssociatedControlID="TextBox_NewEmployeeName"
Text="Employee Name: "></asp:Label>
<asp:TextBox ID="TextBox_NewEmployeeName" runat="server" Width="100%"></asp:TextBox><br />
<br />
<asp:Button ID="SaveEmployee_Button" OnClick="SaveEmployeeBtn_Click" runat="server"
Text="Save" CssClass="ButtonStyle" Style="margin: 0px;" /><br />
</div>
Now have a look at the jQuery definition of the Modal Dialog to be created with
this div:
$("#LocalDialogModal").dialog({
dialogClass: 'dialogStyle',
autoOpen: false,
resizable: false,
draggable: false,
modal: true,
open: function (type, data) {
$(this).parent().appendTo("form");
},
width: 500,
height: 238,
title: "Save Employee"
});
If you closely watch the code snippet above, it is almost same as how you define
any jQuery Modal dialog, but with a small difference in the ‘open’ attribute. We
have a statement like this:
$(this).parent().appendTo("form");
This line is important to make the server side button in the div to function correctly.
What that line does is, it appends the whole content of the rendered html into the
existing form tag of the parent page.
Now, does that confuse you? Yes, it confused me too. If you look at the parent.aspx,
the div ‘LocalDialogModal
’ is already under the form tag. Why do you
have to do an ‘append’ again?
The answer lies in how jQuery handles the dialog windows by default. Even though
you have put the div within the form tag, when you load them, the whole div is rendered
outside the form tag, by default. Hence all the server side elements that got rendered
will not work, if it is not under a form tag.
I will show the rendered html if I haven’t put that one line:
$(this).parent().appendTo("form");
And remember that, this is the default behavior of the jQuery dialog window:
Now when we put the code to append the ‘localDialogModal
’ div into
the form tag, the rendered HTML looks like below:
Now that the server side button comes within the form tag, clicking on it will call
the server side method "SaveEmployeeBtn_Click
" without any problem.
Calling a server side method asynchronously from a jQuery Dialog Window
To achieve async server calls from within the jQuery Dialog window, we might consider
putting the contents of the jQuery Dialog within an asp:UpdatePanel – but this will
not work correctly most of the time. You might encounter problems like Dialog window
getting closed soon after the postback, not able to see updated contents in the
Dialog window itself, the dialog itself getting unhooked, etc.
I am going to show you how to call the a server side method asynchronously without
having to worry about the asp:updatePanel
nuances associated with jQuery
Dialogs.
Let’s consider the first example shown here, wherein we load a totally different
aspx contents into a jQuery Dialog window invoked from a parent page. It will be
very straightforward to assume that we will have buttons in the child aspx content
that has to make server side calls.
Let’s see the code in the DialogContentPage.aspx:
<form id="form1" runat="server">
<div id="MainContentDiv">
Dynamic Dialog Page loaded!
<asp:PlaceHolder ID="DynamicPlaceholder" runat="server"></asp:PlaceHolder>
<input type="button" id="EvaluateButton" value="Evaluate" class="ButtonStyle" />
<br /><br />
<div>
<asp:Label ID="ResultLabel" runat="server" Height="60px" Width="400px" Style="display: none"></asp:Label>
</div>
</div>
</form>
The asp:Placeholder
will hold the table that is generated at runtime
based on the inputs from the user (in our case) or any data that is available with
you at the server.
We have a button ‘EvaluateButton
’. I am going to show you how to call
a server side method on the click of this button along with some inputs, do some
operations on the server and then update the results on the jQuery Dialog window
itself (without closing it) – all asynchronously.
Let’s bind a jQuery method to be called on the click of this button:
$(document).on("click", "#EvaluateButton", function () {
var inputArray = new Array();
$("#DynamicTable").find("input").each(function (index) {
inputArray[index] = $(this).val();
});
var inputArrayList = "{ inputArray: " + JSON.stringify(inputArray) + "}";
$.ajax({
type: "POST",
dataType: "json",
contentType: "application/json",
url: "DialogContentPage.aspx/Evaluate_Click",
data: inputArrayList,
success: function (data) {
if (data.d.indexOf("Error") != -1) {
}
else {
$("#ResultLabel").show();
$("#ResultLabel").text("Sum of all the contents is: " + data.d);
}
},
error: function (e, ts, et) {
alert(ts);
}
}); });
What is being done here is very straightforward. I take all the inputs in the textboxes
within the table generated dynamically, and created a JSON string.
And then, I call a url "DialogContentPage.aspx/Evaluate_Click", with this
JSON string as input.
So what is this url represent? It represents a web method ‘Evaluate_Click
’
defined at the server in DialogContentPage.aspx. Ok, Let’s see that:
[System.Web.Services.WebMethod]
public static string Evaluate_Click(string[] inputArray)
{
string result = string.Empty;
try
{
int resultInt = 0;
foreach (var item in inputArray)
{
var input = int.Parse(item);
resultInt += input;
}
result = resultInt.ToString();
}
catch (Exception exp)
{
result = "error";
}
return result
}
This method is very straightforward – it takes an input of string array, and does
something as simple as adding it up all together. The point here is that, since
this is done at the server side, you can do a whole lot of complex stuff to achieve
some result.
Also remember 2 things:
- This method should be static and should be decorated by the attribute [
System.Web.Services.WebMethod
]
- The input that it takes should be of the same name as defined in the earlier JSON
creator method shown below:
var inputArrayList = "{ inputArray: " + JSON.stringify(inputArray) + "}";
Rest everything is straightforward – Once the web method returns the results successfully,
I append the result to the ResultsLabel
.
I have attached the source code of all the examples shown in this article.
Points of Interest
These are very frequently occurring scenarios that a beginner in jQuery might encounter
and may lose a lot of time trying to achieve it without issues.