Sunday, May 6, 2012

Targeting a select list of recipients of your notification by using jQuery Ajax and ASP.NET


Topics discussed: jQuery, jQuery Ajax, ASP.NET partial page rendering, Javascript

Scenario: This blog explains a case typical of a social web app, where the user can select a list of intended recipients of a publication (e.g.: a blog post, a text message, an email, or some other kind of notification.) This would be a case when the user does not want to share information with the whole community, but rather with only a subset of select users (e.g.: friends, colleagues, followers, group members, etc.)

The page that contains the data-entry form enables the user to select his/her target audience by making behind-the-scenes jQuery Ajax calls to the server and refreshing only a portion of the page’s UI.

Let’s examine the code in different layers of the application:

The Client Code:

It consists of jQuery Ajax calls to a server side ASP.NET code, and Javascript helper methods:
<head>
    …
   1.   $("a#hlSavedList").click(function () {
   2.       var userId = $get('<%=hfUserId.ClientID%>').value;
   3.       var sUrl = "GetRecipientsByAjax.aspx?userId=" + userId;
   4.        $.get(sUrl, function (result) {
   5.                $('#divRecipientList').html(result);
             });
        });
   …
</head>

The above jQuery code executes (line 1 above) when a hyperlink with ID= hlSavedList is clicked. The html of this hyperlink is shown below:

<a href="#links" ID="hlSavedList" name="hlSavedList">Get my list</a>

In order to retrieve the user’s list, we need to reference user’s UserId stored in a hidden field that is placed on the ASP.NET page:
<asp:HiddenField ID="hfUserId" runat="server" />

And jQuery accesses the value of this HiddenField with this line of code (line 2 above):

var userId = $get('<%=hfUserId.ClientID%>').value;

The HiddenField can be assigned the UserId value after the user logs in (in page’s server-side code), and it would look something similar to this:

MembershipUser mu = Membership.GetUser();
Guid guidUserID = new Guid(mu.ProviderUserKey.ToString());
this.hfUserId.Value = guidUserID.ToString();

Alternatively, the UserId can be read from a Session object if it has stored the value earlier:

if (Session[“UserId”] != null)
{
        this.hfUserId.Value = Session[“UserId”].ToString();
}

Next, we can call our target ASP.NET page to do the work and return the HTML markup that will populate only a portion (a <div> element) of the page (lines 3, 4, and 5):

var sUrl = "GetRecipientsByAjax.aspx?userId=" + userId;

$.get(sUrl, function (result) {
      $('#divRecipientList').html(result);
});


The Server Code:
The server code exists in the GetRecipientsByAjax.aspx page’s code-behind, and it will not execute like typical pages, rather it will return only a string representing the DataList’s HTML markup:

protected void Page_Load(object sender, EventArgs e)
{
   if (Request.QueryString["userId"] != null)
   { 
        GetAudienceByUser(Request.QueryString["userId"].ToString());
   }
   else
   {
      Response.Write("<table><tr><td>Error: No query string value in url.</td></tr></table>");
      Response.End();
   }
}

This method binds the data to the DataList control and then calls the helper method GetHtml() which retrieves the controls HTML, places it in the page’s Response and ends the processing on the server by calling Response.End();

 //*******************************************
private void GetAudienceByUser(string userId)
{
   try
   {
      //Get the data from the data source:
      this.dataListAudience.DataSource =
    DataAccessLayer.GetAudienceByUser(userId);
      this.dataListAudience.DataBind();

      if (this.dataListAudience.Items.Count > 0)
      {
          Response.Cache.SetCacheability(HttpCacheability.NoCache);
          string sRet = GetHtml(this.dataListAudience);
          Response.Write(sRet);
      }
      else
      {
          Response.Cache.SetCacheability(HttpCacheability.NoCache);
          Response.Write(@"<table width=""460""><tr><td
                    style=""text-align:center;color:red;height:30px;"">
                    No contacts in your Saved List.
                    </td></tr></table>");
      }
   }
   catch (SqlException sqlEx)
   {
      Response.Cache.SetCacheability(HttpCacheability.NoCache);
      Response.Write("Database Error: " + sqlEx.Message);
   }
   catch (Exception ex)
   {
      Response.Cache.SetCacheability(HttpCacheability.NoCache);
      Response.Write("Generic Error: " + ex.Message);           
   }
   finally
   {
      Response.End();
   }
}

 //*****************************************
public static string GetHtml(Control oCtrl)
{
   StringBuilder sbHtml = new StringBuilder();
   HtmlTextWriter oWriter = new HtmlTextWriter(new StringWriter(sbHtml));

   try
   {
      //Get the control’s HTML
      oCtrl.RenderControl(oWriter);
   }
   finally
   {
      oWriter.Close();
   }
   return sbHtml.ToString();
}

The DataList control in the .aspx page:
<asp:DataList ID="dataListAudience" runat="server"
                         RepeatColumns="2" RepeatDirection="Vertical"
                         DataKeyField="User_Id" EnableViewState="true"
                         Width="500">
    <HeaderTemplate>
        <table width="460" cellpadding="0" cellspacing="0" border="0">
           <tr><td style="height:6px;"></td></tr>
           <tr><td align="center"><strong>Audience List</strong></td></tr>
           <tr><td style="height:10px;"></td></tr>
        </table>
    </HeaderTemplate>                        
    <ItemTemplate>
        <table width="215" cellpadding="0" cellspacing="0" border="0">
           <tr>                                                  
               <td width="215" align="right" valign="bottom">
                   <%# Eval("Email") %>&nbsp;
                   <input type="checkbox" name="audience"
                                value='<%# Eval("AudienceUser_Id") %>'
                                title='<%# Eval("Email") %>' />
               </td>                           
           </tr>                                              
        </table>                            
    </ItemTemplate>
    <FooterTemplate>
        <table width="460" cellpadding="0" cellspacing="0" border="0">
             <tr style="height:20px;"><td></td></tr>
        </table>
     </FooterTemplate>         
</asp:DataList>

 The rendered HTML that is returned to the client is the following text as shown in Fiddler2:

<table id="dataListAudience" cellspacing="0" border="0"
            style="width:500px;border-collapse:collapse;">
<tr>
      <td colspan="2">
            <table width="460" cellpadding="0" cellspacing="0" border="0">
                <tr><td style="height:6px;"></td></tr>
                <tr><td align="center"><strong>Audience List</strong></td></tr>
                <tr><td style="height:10px;"></td></tr>
            </table>
      </td>
</tr>

<tr>
      <td>
          <table width="215" cellpadding="0" cellspacing="0" border="0">
              <tr>
                                                  
                   
<td width="215" align="right" valign="bottom">
                            user0@adventureworks.com&nbsp;

                            <input type="checkbox" checked="checked" name="Audience"
                                        value='44813d2c-b9ac-4a8a-aab1-4a25bba1a466'
                                        title=' user0@adventureworks.com ' />
                   </td>
                           
              
</tr>
                                              
          
</table>
                            
      
</td>

      <td>
           <table width="215" cellpadding="0" cellspacing="0" border="0">
              <tr>
                                                  
                
<td width="215" align="right" valign="bottom">
                    user1@adventureworks.com&nbsp;

                    <input type="checkbox" checked="checked" name="Audience"
                                value='f8213e5b-53d9-4102-9bfa-9363f5ec82b0'
                                title='user1@adventureworks.com' />
                 </td>
                           
             
</tr>
                                              
          
</table>
                            
        
</td>
     </tr>

     <tr>
            <td colspan="2">
                <table width="460" cellpadding="0" cellspacing="0" border="0">

                     <tr style="height:20px;"><td></td></tr>
                </table>
            </td>
     </tr>

</table>


The returned HTML shown in Fiddler2 (the source):


The design view:


The architecture:

No comments:

Post a Comment