Tuesday, December 13, 2011

Enhancing Telerik's RadListBox

As a follow-up to the previous post, I wanted to share the work I've done to add server-side functionality via client-side calls.  Though this example focuses heavily on Telerik controls, what I've developed is completely generic ASP.net code that can be used in any situation where one needs to cause a server-side event but one is not natively available from the control.
The basic challenge I was facing was to allow both single & double clicking in Telerik's RadListBox.  Natively, single-clicks are handled on the server via: OnSelectedIndexChanged.  But there is no server-side equivalent for double-clicks.

Here's what happens when the RadListBox is single-clicked. Eventually a lot more will occur, including a flowchart appearing, unique to each selected item.

When the RadListBox is double-clicked, a popup dialog appears.  In this case it's a RadWindow:

Here's the ASP.Net layout code:


Here's the client-side Javascript, which initially makes heavy use of jQuery to obtain the ListBox object. The key points to note are:
  1. The use of the clickTimer variable to help distinguish between single & double clicks.
  2. The differentiation of click type via the initial parameter of either "1" or "2".
  3. Forcing a server-side postback via ASP.Net's __doPostBack Javascript function.
  4. The first parameter used with __doPostBack is the ID of the AJAX UpdatePanel.  Doing so ensures that a partial, rather than full, postback occurs, which is much more aesthetically pleasing. 

Finally, here's the server-side code that handles the postback forcibly caused by the client. The key points to note are:
  1. The initial checking of the  __EVENTTARGET system variable is very rudimentary.  If multiple such client postbacks existed from different controls then more sophisticated checking could be accomplished..
  2. What parameters are passed is entirely up to the developer.  In this example, passing just the "1/2" and the ListBox index was sufficient. 
    protected void Page_Load(object sender, EventArgs e)
      if (!Page.IsPostBack)
        // The code in this construct strictly handles the single & double clicking of the RadListBox
        if (this.Request["__EVENTTARGET"].EndsWith("UpdatePanel1"))
          string parameters = this.Request["__EVENTARGUMENT"];

          if (parameters != "")
            // This event may have been fired by either a single-click or a double-click.  We need to 
            // find out which one.  The first parameter will be either "1" or "2", indicating which.
            string[] sParamArray = parameters.Split(new char[] { ',' });

            int idx = Convert.ToInt32(sParamArray[1]);
            if (sParamArray[0] == "1") // Single-click

Saturday, December 10, 2011

Retrieving a Nested ASP.Net Object with Javascript & jQuery

Though I consider myself to be an accomplished C# / ASP.Net web developer, one of my weaknesses lies with client-side Javascript programming. I don't like the free-form, type unsafe nature of it and firmly believe that long term maintainability of Javascript code is a nightmare. The introduction of jQuery has improved things somewhat but there are still times when things can get very tricky. One prime example involves working with nested ASP.Net controls. Here's a quick example of such a situation:

What you're seeing in this image are a number of Telerik controls (which I highly recommend!) that provide a superb user experience for the application I'm building.
My task at hand was to add some custom client-side code for when an item in the listbox was double-clicked.

Here's a snippet of the layout code for the page:

The challenge was to obtain the ListBox from within the nested objects. Here's a sample Javascript function, that utilizes jQuery, to retrieve the RadListBox object:
 function rlbDoubleClicked() {
   var slidingZone = $find($('table[id$=_radSlidingZone]')[0].id);
   var slidingPane = slidingZone.getPanes()[0];

   // Standard Approach
   var listBox = $find($("#" + slidingPane.get_id() + " #<%= radListBoxStopes.ClientID %>")[0].id);

   // Alternate Approach (necessary if the function is to be placed in an external Javascript file)
   var listBox = $find($("#" + slidingPane.get_id() + " div[id$=_radListBoxStopes]")[0].id);
Hopefully this example will help others with their own projects!