Problem

The accordion control provided by the Ajax Control Toolkit is a great control to display expandable items in a list. Depending on the amount of data you want to display when an item is expanded, the page that contains the control can quickly become huge because you have to load in the page all the data shown in the expanded version of all the items.

Solution

Here comes the Load On Demand accordion control !

Instead of loading all the data up front, it fetches the data of the selected item only using Ajax.

imageimage

Overview

On your page, you will have two invisible panels, one that contains the html code you want to display whenever you are loading an item, and a second that is wrapped in an UpdatePanel control, that will retrieve the html code of the selected item. When the ajax request of the UpdatePanel finishes, you simply copy the content into the content panel of the selected item.

On the asp.net side

The code I use for the invisible loading panel:

<div id=”loadingPanel” class=”invisible”>
    <img src=’ajax-loader.gif’ /> Loading…
</div>

The code I use for the update panel:

<asp:UpdatePanel ID=”updatePanel” runat=”server”>
    <ContentTemplate>
        <p>Invisible update panel:
        <div class=”invisible”>
            <asp:Panel ID=”panelUpdated” runat=”server”>
               <uc1:DetailedPlayerView ID=”detailedPlayerView” runat=”server” />
            </asp:Panel>
            <asp:HiddenField ID=”hiddenPlayerId” runat=”server”/>
            <asp:Button ID=”btnUpdate” OnClick=”btnUpdate_PlayerView” runat=”server” Text=”Button” class=”invisible”/>
        </div>
        </p>
    </ContentTemplate>
</asp:UpdatePanel>

When a user clicks on the header of an item, a javascript function is called, performing the following actions:

- Save the selected panel in a javascript variable to refer to it when the callback function is called

- Store the selected data item id in an hidden field (to be able to display data specific to that id)

- Copy the content of the loading panel into the content panel of the selected item

- Click the button btnUpdate to update the UpdatePanel.

The javascript code looks like this:

var selectedContentPanel = “”;

function fetchContent(contentPanel, playerID)
{
    // save selected panel
    selectedContentPanel = contentPanel;
    // save playerId value in hidden field
    $get(“<%= hiddenPlayerId.ClientID%>”).value = playerID;
    // show the loading picture
    $get(contentPanel).innerHTML = $get(“loadingPanel”).innerHTML;
    // call postback
    $get(“<%= btnUpdate.ClientID%>”).click();
}

You need to subscribe to the endRequest events to be able to update the content panel based on the UpdatePanel content:

Sys.WebForms.PageRequestManager.getInstance().add_endRequest(EndRequestHandler);

function EndRequestHandler(sender,args)
{
    // update selected panel with postback result
   $get(selectedContentPanel).innerHTML = $get(“<%= panelUpdated.ClientID %>”).innerHTML;
}

On the C# side

You can update the content of the UpdatePanel in the event handler of the Click event of the invisible button in the UpdatePanel

protected void btnUpdate_PlayerView(object sender, EventArgs e)
{
    var playerId = long.Parse(hiddenPlayerId.Value);
    var player = _players.Find(x => x.PlayerId == playerId);
    detailedPlayerView.Player = player;
}

Calling fetchContent

To be able to call the javascript fetchContent method when the header is clicked, you need to add a onClick attribute. Because I want to be able to pass the id of the content panel, I found it easier to add the onClick attribute on the C# side.

I subscribed to the ItemDataBound event of the Accordion control and handled it this way:

protected void accordionPlayers_ItemDataBound(object sender, AccordionItemEventArgs e)
{
    if (e.AccordionItem.ItemType == AccordionItemType.Content)
    {
        var player = (PlayerInfo)e.Item;
        var contentPanel = (Panel)e.AccordionItem.FindControl(“panelContent”);
        var headerPanel = (Panel)e.AccordionItem.Parent.Controls[0].FindControl(“panelHeader”);
        // add to the header panel an onclick attribute that passes the id of the player and the content panel
        var fetchContent = string.Format(“fetchContent(\”{0}\”, {1});”, contentPanel.ClientID, player.PlayerId);
        headerPanel.Attributes.Add(“onclick”, fetchContent);
    }
}

I hope you will find this blog post useful, don’t hesitate to leave a comment!

Cheers

2 Responses to “Load On Demand Accordion control for Asp.net Ajax”

  1. eanirudh Says:

    hi, thanks for providing such a use full code.
    =================================================
    http://eanirudh.wordpress.com
    ================================================

  2. itsurshailesh Says:

    hi,
    this is really a good article, can u let me know how to bind data on Onclick event of accordion control. so I wish to bind only one accordion content at a time.
    and let me know, if u have any examples for accordion control.
    Thanks!


Leave a Reply