Saturday, February 5, 2011

ScriptManager.RegisterDataItem to update control outside UpdatePanel

Hi Friends

Today I would like to share an interesting stuff with Ajax. I have seen many of my colleague to use 2 Different UpdatePanel when they want to update a DataBind control and just a single value on the page but outside of UpdatePanel.

Consider a scenario where you are creating a sample application to provide comments threading. And main thread will show total number of comments. Check the sample layout if as below.

image

So here we have a main thread on the top, below that Total Comments which needs to be updated. There are many ways to do this.

1. Put whole page in UpdatePanel. Each and every content will be updated. This is the easiest way.

2. Put the repeater  of comments and Textbox in one UpdatePanel and Total comments in another UpdatePanel. (In this simple layout we may not require, but in real life scenario we have much more complex layout where it could not be possible every time)

3. As we just want to update number of comments in a label. We can use ScriptManager.RegisterDataItem method.

ScriptManager.RegisterDataItem method have 2 override signatures.

1. ScriptManger.RegisterDataItem(Control control, string dataItem)

2. ScriptManager.RegisterDataItem(Control control, string dataItem, bool isJsonSerialized)

This method can be accessed from instance of ScriptManager.

Here is the use of each parameter

control: You need to pass your control for which you are registering the data item

dataItem: String value which will be passed as value to your script manager on client side.

isJsonSerialized: With this Boolean value you can specify that whether string value which you have set as data item is serialized as JSON format.

 

Now, how  does this RegisterDataItem works. RegisterDataItem register a data key and its value while responding to your asynchronous request. Now on client side you need to handle pageLoading event of the script manager.

Here is the code which we will write to achieve output as screenshot.

HTML required

<asp:ScriptManager ID="ScriptManager1" runat="server">
</asp:ScriptManager>
<table>
    <tr>
        <td>
            Hi this is main thread users are commenting on this post.
        </td>
    </tr>
    <tr>
        <td>
            Total Comments:
            <asp:Label ID="lblShowData" runat="server" Text="0"></asp:Label>
        </td>
    </tr>
    <tr>
        <td>
            <asp:UpdatePanel ID="updData" runat="server">
                <ContentTemplate>
                    <table>
                        <tr>
                            <td>
                                <asp:Repeater ID="rptComments" runat="server">
                                    <HeaderTemplate>
                                        <ul>
                                    </HeaderTemplate>
                                    <ItemTemplate>
                                        <li>
                                            <%# Container.DataItem %></li>
                                    </ItemTemplate>
                                    <FooterTemplate>
                                        </ul></FooterTemplate>
                                </asp:Repeater>
                            </td>
                        </tr>
                        <tr>
                            <td>
                                <asp:TextBox ID="txtData" runat="server" TextMode="MultiLine"></asp:TextBox>
                            </td>
                        </tr>
                        <tr>
                            <td>
                                <asp:Button ID="btnSubmit" Text="Submit" runat="server" OnClick="btnSubmit_Click" />
                            </td>
                        </tr>
                    </table>
                </ContentTemplate>
            </asp:UpdatePanel>
        </td>
    </tr>
</table>

JavaScript to handle pageLoading event and set data

var pageReqManger = Sys.WebForms.PageRequestManager.getInstance();
pageReqManger.add_pageLoading(OnPageLoading);
/// To execute on page loading while async postback
function OnPageLoading(sender, args) {
    var dataItems = args.get_dataItems();
    if ($get('lblShowData') !== null)
        $get('lblShowData').innerHTML = dataItems['lblShowData'];

}

In javascript we have firstly retrieved the instance of our script manager. Then we have added pageLoading hander. Now when this handler is called you can get the dataitems in the arguments. So we have get the data item for lblShowData and assign it as innerHTML of the control.

C# code for store and binding

public List<string> Comments
{
    get
    {
        List<string> lstComments = Cache["keyComments"] as List<string>;

        if (lstComments == null)
        {
            lstComments = new List<string>();
            Comments = lstComments;
        }
        return lstComments;
    }
    set { Cache["keyComments"] = value; }
}

protected void Page_Load(object sender, EventArgs e)
{
    if (!IsPostBack)
    {
        lblShowData.Text = Comments.Count.ToString();
        rptComments.DataSource = Comments;
        rptComments.DataBind();
    }
}
protected void btnSubmit_Click(object sender, EventArgs e)
{
    // Add comment to list
    Comments.Add(txtData.Text);

    //Bind list to repeater
    rptComments.DataSource = Comments;
    rptComments.DataBind();

    // register data item to scriptmanager
    ScriptManager1.RegisterDataItem(lblShowData, Comments.Count.ToString());

    // set the string empty
    txtData.Text = string.Empty;
}

We have registered the data item in click event of the button. With our ScriptManager1 for lblShowData with the values of our total comments. As we only have simple number to display we have not pass the third parameter for json serialization.

If we think of more scenario we can use this method in many ways.

Let me know in case you have query on this method.

Thanks

Nirav