Thursday, February 11, 2010

Open popup windows in IE/Firefox and return values using ASP.NET and Javascript

With the forums flooded with questions of opening a popup window, passing values to the popup window and then return values back to the parent page using both Internet Explorer and Firefox, I decided to take a plunge into the subject and experiment with an easy implementation. This article explains how to transfer values between the Parent page and a Pop-up window. The code has been tested against IE7 and Firefox.
Internet Explorer(IE) contains the showModalDialog() method which proves very effective while creating a modaldialog box and displaying a html document in it. One caveat being,showModalDialog() is not a W3C implementation. So it is not supportedin Firefox (as of version 2.0.0.11). Firefox supports the window.open()method. However there is no built in functionality in Firefox thatkeeps the popup modal. At the most, you can use ‘modal=yes’ to make the popup appear in front. However unlike the showModalDialog() in IE, you cannot restrict the user to access the parent page when the popup is opened in Firefox. In short, it is not truly modal. There are different ways to get around this problem, however in this article, we will only focus on exchanging values between the parent and popup page.
In this article, we will see how to take a simple approach and create a popup window using both IE and Firefox. In the first part, we will pass in the first name from the parent page to the popup window. In the second part, the popup window will reverse the name and return there versed string to the parent window. All set!! Let us get started.
Part 1 - Passing value to Popup window
Step 1: Open Visual Studio. Create a new website (File > New > Website). Set the location, filename and language of the project.
Step 2:In your Default.aspx, add a label (lblFName), textbox (txtFName) and abutton (btnPopup). Set the ‘Text’ property of the label to ‘FirstName’.Similarly set the ‘Text’ property of the button control to ‘Show Popup’.
Step 3:Now add the popup form. Right click your project > Add New Item >Web Form > Rename form as ‘PopupWin.aspx’ and click on Add.
Step 4: In the PopupWin.aspx, add a textbox (txtReverse) and a button (btnReverse).
Wellnow we have two pages, Default.aspx which is the parent page andPopupWin.aspx which will be the popup page. Let us now pass a valuefrom Default.aspx to the popup window.
Step 5:We will invoke the popup window on the button (btnPopup) click ofDefault.aspx. To do so, we will use Button.Attribute.Add and call ajavascript function that will open the popup window. The javascriptfunction will be contained in a seperate pop.js file which we willcreate shortly. Add this code in the code behind file of yourDefault.aspx.
C#
protected void Page_Load(object sender, EventArgs e)
    {
        btnPopup.Attributes.Add("onClick", "javascript:InvokePop('" + txtFName.ClientID + "');");
    } 
VB.NET
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        btnPopup.Attributes.Add("onClick", "javascript:InvokePop('" & txtFName.ClientID & "');")
    End Sub
Over here we are passing the ClientID of the textbox. ClientID is the identifier of the server control, generated by ASP.NET. You must be wondering why I am not passing the value of the textbox directly. Well passing the control has an advantage where there is more than one control that is passed to the popup page. While returning back the values from the popup to the parent page; it helps you to decide and determine which control receives which value. Even though we will be using only one textbox for simplicity, I thought of creating a sample which can be extended later by you to suit your needs. If the use ofClientID is not clear to you, wait till we get to part 2 of thisarticle, and I will again touch upon the subject.
Step 6:Let us now create the javascript functionality which will open thePopup. Right click your project > Add New Item > Jscript file> Rename the file to pop.js. Add the following function to thepop.js file
function InvokePop(fname)
{
        val = document.getElementById(fname).value;
        // to handle in IE 7.0          
        if (window.showModalDialog)
        {      
            retVal = window.showModalDialog("PopupWin.aspx?Control1=" + fname + "&ControlVal=" + val ,'Show Popup Window',"dialogHeight:90px,dialogWidth:250px,resizable:
yes,center:yes,");
            document.getElementById(fname).value = retVal;
        }
        // to handle in Firefox
        else
        {     
            retVal = window.open("PopupWin.aspx?Control1="+fname + "&ControlVal=" + val,'Show Popup Window','height=90,width=250,resizable=yes,modal=yes');
            retVal.focus();           
        }         
}
This function accepts the textbox control, retrieve’s the value of the textbox that needs to be reversed and passes the textbox control and its value to PopupWin.aspx through query string. This is the function which will be called on the btnPopup click.
Step 7: To wire up the .js with your asp.net pages, add a link to the javascript file in both the pages as shown below:
Default.aspx
<head runat="server">
    <title>Parent Page</title>
    <script type="text/javascript" src="pop.js"></script>
</head>
PopupWin.aspx
<head runat="server">
    <title>Popup Page</title>
    <script type="text/javascript" src="pop.js"></script>
</head>
Step 8:In the code behind file of PopupWin.aspx, add the following code at the Page_Load() to retrieve the value from the querystring and display the value in the TextBox ‘txtReverse’, placed in the popup window.
C#
protected void Page_Load(object sender, EventArgs e)
    {
        txtReverse.Text = Request.QueryString["ControlVal"].ToString();
    }
VB.NET
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        txtReverse.Text = Request.QueryString("ControlVal").ToString()
    End Sub
If you are eager to test the value going from Parent page to the popupwindow, you can do so now. Make Default.aspx as ‘Set as Start page’ andrun the sample. Enter your name in txtFName TextBox and click on ShowPopup button. A popup window opens with the value entered in the Parentpage.
Part 2 - Passing value from Popup window to the Parent page
In this second part, we will reverse the string and pass the reversed string back to the parent page. To do so, follow these steps:
Step 1: Add additional functions to the pop.js file which will reverse the string and return the string back to the parent page.
// pop.js
function ReverseString()
{
         var originalString = document.getElementById('txtReverse').value;
         var reversedString = Reverse(originalString);
         RetrieveControl();
         // to handle in IE 7.0
         if (window.showModalDialog)
         {             
              window.returnValue = reversedString;
              window.close();
         }
         // to handle in Firefox
         else
         {
              if ((window.opener != null) && (!window.opener.closed))
              {              
                // Access the control.       
                window.opener.document.getElementById(ctr[1]).value = reversedString;
              }
              window.close();
         }
}
function Reverse(str)
{
   var revStr = "";
   for (i=str.length - 1 ; i > - 1 ; i--)
   {
      revStr += str.substr(i,1);
   }
   return revStr;
}
function RetrieveControl()
{
        //Retrieve the query string
        queryStr = window.location.search.substring(1);
        // Seperate the control and its value
        ctrlArray = queryStr.split("&");
        ctrl1 = ctrlArray[0];
        //Retrieve the control passed via querystring
        ctr = ctrl1.split("=");
}
As you saw in part 1, the value was passed from the parent window to the popup window and was kept in the txtReverse TextBox. The functionReverseString() retrieves the value from this textbox and passes the string to the Reverse() function which reverses the string. There versed string is then kept in the ‘reversedString’ variable. The ‘RetrieveControl’ splits the query string and identifies the control in the parent page to which the reversed string value is tobe sent.
Note:If you observe, in the IE implementation, I am not really making use of the RetrieveControl(), however in Firefox I am. If you remember, in theb eginning of part1 , I had mentioned the use of ClientID, using which both controls and their values can be passed to determine which control recieves which value. This is especially needed when there are multiple controls. Well the RetrieveControl seperates the different controls and you can use the variables in this method to return values to there spective contro.l
The value is then returned to the parent window and the popup window is closed.
Step 2:Now in order to use these newly added javacript functions, just call the ReverseString() function on the btnReverse click. To do so, add the onclick attribute to the btnReverse.
<input class="button" type="button" id="btnReverse" value="Reverse value back" onclick="ReverseString();"/>
That’s it. Now test the code. Pass your name from the Parent window to the Popup window and then reverse the string and pass it back to the Parentwindow.
I would like to mention that there are multiple ways of doing the task demoed in this article. I have seen some cool examples by experts. One of them I would like to mention is that of NC01where he makes use of properties and ViewState, to pass values to the Popup window. I would encourage you to use this article as a base and ry out your own implementations that would work on multiple browsers.
The source code of this article, both in C# and VB.NET, can be downloaded from here. I hope this article was useful and I thank you for viewing it.

Moving data between two ListBoxes - Difference between jQuery 1.3.2 and jQuery 1.4

Recentlya new version of jQuery was released. This version is 1.4. As with anynew version, ultimately you see what used to take you several lines ofcode, now rolled up into a single line of code. I'm going todemonstrate a question I've been asked many times on forums and that ishow to move selected items from one<select> element toanother. I'll show you how you could do it using jQuery 1.3.2 and howto minimize the code by using the new 1.4 library. Before we begin, thenew version can be found here.
The HTML
TheHTML for this is pretty straight forward. It's simply two<select> elements side by side with two buttons betweenthem. Here's what it looks like:
Move data between two listboxes
<form method="get">             
      <select id="SelectLeft" multiple="multiple">
            <option value="1">Australia</option>
            <option value="2">New Zealand</option>
            <option value="3">Canada</option>
            <option value="4">USA</option>
            <option value="5">France</option>
      </select>
           
      <input id="MoveRight" type="button" value=" >> " />
      <input id="MoveLeft" type="button" value=" << " />
       
      <select id="SelectRight" multiple="multiple">          
      </select>
</form>
jQuery 1.3.2
Below is the code to move the selected items from each <select> element. 
<script language="javascript" type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>   
    <script language="javascript" type="text/javascript">
        $(function() {
            $("#MoveRight,#MoveLeft").click(function(event) {
                var id = $(event.target).attr("id");
                var selectFrom = id == "MoveRight" ? "#SelectLeft" : "#SelectRight";
                var moveTo = id == "MoveRight" ? "#SelectRight" : "#SelectLeft";
                var selectedItems = $(selectFrom + " :selected");
                var output = [];               
                $.each(selectedItems, function(key, e) {                   
                  output.push('<option value="' + e.value + '">' + e.text + '</option>');
                                });
               
                $(moveTo).append(output.join(""));               
                selectedItems.remove();
            });
        });
    </script>
I'vebound one event handler for the button clicks. To decide whichdirection the selected items should go, I'm using the ID of the buttonthat fired the event:
var id = $(event.target).attr("id");
var selectFrom = id == "MoveRight" ? "#SelectLeft" : "#SelectRight";
var moveTo = id == "MoveRight" ? "#SelectRight" : "#SelectLeft";
Next I create an empty array and loop through every selected item and add it to the end of the array:
var output = [];               
$.each(selectedItems, function(key, e) {                   
      output.push('<option value="' + e.value + '">' + e.text + '</option>');
});
Then I append it to the end of the <select> element and remove the moved items:
$(moveTo).append(output.join(""));               
selectedItems.remove();
Overall I think that's a good approach. In jQuery 1.4 we can make this better!
jQuery 1.4
In the new jQuery library, the team has introduced a new function called toArray. This retrieves all the DOM elements contained in the jQuery set, as an array. So here's the code below:
<script language="javascript" type="text/javascript" src="http://code.jquery.com/jquery-1.4.1.min.js"></script>
    <script language="javascript" type="text/javascript">
        $(function() {
            $("#MoveRight,#MoveLeft").click(function(event) {
                var id = $(event.target).attr("id");
                var selectFrom = id == "MoveRight" ? "#SelectLeft" : "#SelectRight";
                var moveTo = id == "MoveRight" ? "#SelectRight" : "#SelectLeft";
                var selectedItems = $(selectFrom + " :selected").toArray();
                $(moveTo).append(selectedItems);
                selectedItems.remove;
            });
        });
    </script> 
The first thing you'll notice is the code has been reduced. Thanks to the toArray function, I have eliminated the need to loop through the selected items. Now they're returned as an array:
var selectedItems = $(selectFrom + " :selected").toArray();
And to add them to the <select> element, I no longer need to use the join function, I simply append them:
$(moveTo).append(selectedItems);
 Nice and simple! The entire source code of this article can be downloaded over here

AutoScroll an ASP.NET Multiline TextBox using jQuery

Thisarticle demonstrates how to autoscroll a multiline textbox both upwardsand downwards using jQuery 1.3.2. This article is a sample chapter frommy EBook called 51 Tips, Tricks and Recipes with jQumry and ASP.NET Controls. The chapter has been modified a little to publish it as an article.


Notethat for demonstration purposes, I have included jQuery code in thesame page. Ideally, these resources should be created in separatefolders for maintainability. The code shown below has been tested onIE7, Firefox 3, Chrome 2 and Safari 4


Let us quickly jump to the solution and see how to AutoScroll a multiline textbox
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
    <title>AutoScroll a Multiline TextBox</title>
    <script type="text/javascript"
     src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js">
    </script>


    <script type="text/javascript">
        $(function() {
            var $tb = $('textarea[id$=tb1]');
            $('input[id$=btnScroll]').toggle(
            function(e) {
                e.preventDefault();
                scrollArea($tb, $tb[0].scrollHeight);
            },


            function(e) {
                e.preventDefault();
                scrollArea($tb, 0);
            });
        });


        function scrollArea(ctrl, ht) {
            ctrl.animate({ scrollTop: ht }, 1000);
        }
    </script>
</head>
<body>
    <form id="form1" runat="server">
    <div class="smallDiv">
        <h2>Scroll the box contents by clicking on the Button</h2>
        <br /><br />
        <asp:TextBox ID="tb1" runat="server" TextMode="MultiLine"
        Text="Lorem Ipsum Lorem Ipsum Lorem Ipsum Lorem Ipsum Lorem
        Lorem Ipsum Lorem Ipsum Lorem Ipsum Lorem Ipsum Lorem Ipsum
        Lorem Ipsum Lorem Ipsum Lorem Ipsum Lorem Ipsum Lorem Ipsum
        Lorem Ipsum Lorem Ipsum Lorem Ipsum Lorem Ipsum Lorem Ipsum
        Lorem Ipsum Lorem Ipsum Lorem Ipsum Lorem Ipsum Lorem Ipsum"
        Rows="5"/>
        <br />
        <asp:Button ID="btnScroll" runat="server" Text="Scroll"/>
        <br /><br />
        Tip: The Text can be scrolled both downwards and upwards.
    </div>
    </form>
</body>
</html>
Whenthe user clicks on the button (btnScroll), we toggle the clickbehavior. On the first click, we cancel the postback by using e.preventDefault() and then call a function called scrollArea() passing in the textarea and the scrollHeight. The code $tb[0].scrollHeight is for scrolling downwards
e.preventDefault();
scrollArea($tb, $tb[0].scrollHeight);
Whenthe user clicks the button (btnScroll) again, the postback is cancelledand the scrollHeight is set to 0 (zero). This is done for scrollingupwards.
e.preventDefault();
scrollArea($tb, 0);
ThescrollArea() function accepts the textarea that is to be scrolled aswell as the scrollHeight. We then animate the scrollTop property toscroll upwards/downwards depending on the height parameter. Theduration of the animation is set to 1000 milliseconds which provides asmooth scrolling effect
function scrollArea(ctrl, ht) {
    ctrl.animate({ scrollTop: ht }, 1000);
}
The code here assumes that you are not scrolling the textarea manually and then clicking the Scroll button.
You can see a Live Demo over here.


I hope you found this article useful and I thank you for viewing it. This article was taken from my EBook called 51 Tips, Tricks and Recipes with jQuery and ASP.NET Controls which contains similar recipes that you can use in your applications.

Call Server Side function from Client Side Code using PageMethods in ASP.NET AJAX

You cannot call server-side code ‘directly’ from client-side code. That isbecause by design, the server side code executes at server side andclient side code at the client. However there are some workarounds. Tocall serverside code from javascript, you will need to use AJAX, andthe easiest way out, is to use the ASP.NET AJAX Extensions.
Oneoption while using Microsoft ASP.NET AJAX is to call ASP.NET Webservices (.asmx files) from the browser by using client script. Thescript can call a webservice containing server-based methods (Webmethods) and invoke these methods without a postback and withoutrefreshing the whole page. However this approach could be overkillsometimes, to perform the simplest of tasks. Moreover the logic needsto be kept in a separate .asmx file. We need something that is more‘integrated’ with our solution.
Theoption we are going to use in this article involves PageMethods. APageMethod is basically a public static method that is exposed in thecode-behind of an aspx page and is callable from the client script.PageMethods are annotated with the [WebMethod] attribute. The pagemethods are rendered as inline JavaScript.
Letus explore PageMethods with an example. The example we will bediscussing here may not be the best example to explain PageMethods, butit will give you an idea of how to call server side code from clientside. In this example, we will be connecting to the Customers table inthe Northwind database. We will have some textboxes which will acceptthe CustomerID and in turn return the Contact Name of that Customer.The method returning ContactName will be called whenever the textboxloses focus. We will be using the onblur event where a javascript codewill take in the value(CustomerID) from the textbox. This javascriptfunction will then call a PageMethod (server side code) which returnsthe ContactName without any page refresh.
Iassume that you have downloaded and installed ASP.NET AJAX extensionsfor ASP.NET 2.0. If not, I would advise you to download the extensionsfrom hereand install it before moving ahead. At any point of time, if you find adifficulty in understanding the code, download the sample projectattached with this article at the end.
Step 1:Create an ASP.NET AJAX enabled website. Go to File > New >Website > ASP.NET AJAX-Enabled Web Site. Give the solution a nameand location and click Ok.
Step 2:Drag and drop 2 labels and 4 textbox controls. We will be accepting theCustomerID from the user in the 2 textboxes and displaying the‘ContactName’ in the other two textboxes. The textboxes that willdisplay ‘ContactName’ has some properties set that will make it appearas a label without a border. Just set the BorderStyle=None,BorderColor=Transparent and ReadOnly=True. The markup will look similarto the following:
<form id="form1" runat="server">    
        <asp:ScriptManager ID="ScriptManager1" runat="server"/>
        <div>
        <asp:Label ID="lblCustId1" runat="server" Text="Customer ID 1"></asp:Label>
        <asp:TextBox ID="txtId1" runat="server"></asp:TextBox><br />
            <asp:TextBox ID="txtContact1" runat="server" BorderColor="Transparent" BorderStyle="None"
                ReadOnly="True"></asp:TextBox><br />
        <br />
        <asp:Label ID="lblCustId2" runat="server" Text="Customer ID 2"></asp:Label>
        &nbsp;
        <asp:TextBox ID="txtId2" runat="server"></asp:TextBox><br />
            <asp:TextBox ID="txtContact2" runat="server" BorderColor="Transparent" BorderStyle="None"
                ReadOnly="True"></asp:TextBox>&nbsp;<br />
            </div>
    </form>
Before moving ahead, we will store our connection string information in the Web.config. Add the following tag below your </configSections> tag. Remember we have created an ‘ASP.NET AJAX enabled website’. The tag </configSections> along with some other tags automatically get added to the web.config.
<connectionStrings>
            <removename="all"/>
            <addname="NorthwindConnectionString"connectionString="Data Source=(local); Initial Catalog=Northwind; Integrated Security = SSPI;"/>
      </connectionStrings>
Step 3:Currently we will add a method, ‘GetContactName()’ which will accept aCustomerID and return the Contact Name information from the Northwinddatabase, Customer table. We will then transform this method as aPageMethod.
C#
public static string GetContactName(string custid)
    {
        if (custid == null || custid.Length == 0)
            return String.Empty;
        SqlConnection conn = null;
        try
        {
            string connection = ConfigurationManager.ConnectionStrings["NorthwindConnectionString"].ConnectionString;
            conn = new SqlConnection(connection);
            string sql = "Select ContactName from Customers where CustomerId = @CustID";
            SqlCommand cmd = new SqlCommand(sql, conn);
            cmd.Parameters.AddWithValue("CustID", custid);
            conn.Open();
            string contNm = Convert.ToString(cmd.ExecuteScalar());
            return contNm;
        }
        catch (SqlException ex)
        {
            return "error";
        }
        finally
        {
            conn.Close();
        }
    }
VB.NET
 Public Shared Function GetContactName(ByVal custid As String) As String
        If custid Is Nothing OrElse custid.Length = 0 Then
            Return String.Empty
        End If
        Dim conn As SqlConnection = Nothing
        Try
            Dim connection As String = ConfigurationManager.ConnectionStrings("NorthwindConnectionString").ConnectionString
            conn = New SqlConnection(connection)
            Dim sql As String = "Select ContactName from Customers where CustomerId = @CustID"
            Dim cmd As SqlCommand = New SqlCommand(sql, conn)
            cmd.Parameters.AddWithValue("CustID", custid)
            conn.Open()
            Dim contNm As String = Convert.ToString(cmd.ExecuteScalar())
            Return contNm
        Catch ex As SqlException
            Return "error"
        Finally
            conn.Close()
        End Try
    End Function
Step 4:We will now transform this method as a PageMethod and then call thismethod GetContactName() from client side code; i.e. using JavaScript.To enable the method as a PageMethod, add the attribute [WebMethod] ontop of the method:
C#
[System.Web.Services.WebMethod]
public static string GetContactName(string custid)
{
}
VB.NET
<System.Web.Services.WebMethod()> _
    Public Shared Function GetContactName(ByVal custid As String) As String
   End Function
At the sametime, add the attribute EnablePageMethods="true" to the ScriptManager as shown below:
<asp:ScriptManager ID="ScriptManager1" runat="server" EnablePageMethods="true"/>
Step 5:Let us now create the JavaScript that will call this server side code.Add a javascript file called script.js to your solution (Right ClickProject > Add New Item > Jscript File > Rename file toscript.js). Add the following code to the javascript file.
function CallMe(src,dest)
 {    
     var ctrl = document.getElementById(src);
     // call server side method
     PageMethods.GetContactName(ctrl.value, CallSuccess, CallFailed, dest);
 }
 // set the destination textbox value with the ContactName
 function CallSuccess(res, destCtrl)
 {    
     var dest = document.getElementById(destCtrl);
     dest.value = res;
 }
 // alert message on some failure
 function CallFailed(res, destCtrl)
 {
     alert(res.get_message());
 }
Step 6:We now need to reference this JavaScript file from our aspx page andinvoke the ‘CallMe()’ method whenever the textbox loses focus. To do so:
Add a reference to the javascript file in the body tag as shown below:
<body>
<script type="text/javascript" language="javascript" src="script.js"> </script>
    <form id="form1" runat="server">    
………
Step 7: To invoke the methods whenever the textbox looses focus, add these lines of code in the Page_Load() event
C#
if (!Page.IsPostBack)
        {
            txtId1.Attributes.Add("onblur", "javascript:CallMe('" + txtId1.ClientID + "', '" + txtContact1.ClientID + "')");
            txtId2.Attributes.Add("onblur", "javascript:CallMe('" + txtId2.ClientID + "', '" + txtContact2.ClientID + "')");
        }
VB.NET
If (Not Page.IsPostBack) Then
                 txtId1.Attributes.Add("onblur", "javascript:CallMe('" &txtId1.ClientID & "', '" & txtContact1.ClientID & "')")
                 txtId2.Attributes.Add("onblur", "javascript:CallMe('" &txtId2.ClientID & "', '" & txtContact2.ClientID & "')")
End If
Asshown above, we are using the Attributes.Add that lets us add anattribute to the server control’s System.Web.UI.AttributeCollectionobject. The function ‘CallMe’ kept in the ‘script.js’ file will beinvoked. We are passing the source and destination textboxes asparameters. The source textbox will contain the CustomerID. TheCustomerID will be looked up in the Customers table and thecorresponding ‘ContactName’ will be retrieved in the destinationtextbox.
Wellthat is all that is needed to invoke server side code from client side.Run the code. Type ‘ALFKI’ in the first textbox and hit the tab key.You will see that the javascript function goes ahead and calls thePageMethod GetContactName() using PageMethods.GetContactName. Itpasses the value of the source textbox which contains the CustomerID.The ‘ContactName’ returned is displayed in the second textbox below thefirst one, in our case the value displayed is ‘Maria Anders’.