May
25
2009

Running specific JavaScript after partial postback

I know how to run JavaScript after every postback, but on occasion I want to run some JS after a specific postback (i.e. show a flash message message that says the processing completed successfully). This hasn’t been as simple as I thought it should be. I even posted to StackOverflow to see if there was something I was missing or if it really is this messy. The only answer I’ve received to date suggested the method I already had in mind when posting the question, so I thought I would work out the full example and show you how it looks.

Background: First a little background. I have a UserControl that I use to display a nice status and/or error message on all my pages. It’s in the master page and has some really convenient JavaScript to show it. For all the ajaxy stuff we do it works great. It flashes in and fades out; however, we can’t show it on the partial postback events…yet. We need to run some JS on the client side after the postback is done to either show the error message or success message.

Overview: Basically, we are going to put a hidden field on the page and register an event handler to run after partial postback to see if there is any JavaScript in it, and execute there is. Pretty simple.

I created a user control to hold all the hidden fields and JS to register the postback events. It is going to get reused in a lot of places so it makes sense to make it reusable. It could be made into a server control, but I’ll forgo that for now.

There isn’t much to the user control.

<%@ Control Language="C#"
    AutoEventWireup ="true"
    CodeFile        ="DoAfterPostback.ascx.cs"
    Inherits        ="DoAfterPostback" %>        

<asp:HiddenField ID="DoAfterPostbackJavaScriptHiddenField" runat="server"
    EnableViewState="false" />

It’ll need some code to create a property to access the JavaScript we want to run and register the event handlers.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

public partial class DoAfterPostback : System.Web.UI.UserControl
{
    public string DoAfterPostbackJavaScript { get; set; }

    protected void Page_Load(object sender, EventArgs e)
    {
        Page.ClientScript.RegisterStartupScript(
            this.GetType(),
            "DoAfterPostbackJavaScriptEngine",
            @"
                var prm = Sys.WebForms.PageRequestManager.getInstance();
                prm.add_endRequest(function(s, e) {
                    $('[id$=_DoAfterPostbackJavaScriptHiddenField]').each(doPostbackJS);
                }); 

                function doPostbackJS(i){
                    eval(this.value);
                }

            ",true);
    }

    protected override void OnPreRender(EventArgs e)
    {
        base.OnPreRender(e);
        DoAfterPostbackJavaScriptHiddenField.Value = DoAfterPostbackJavaScript;
    }
}

We probably don’t need jQuery in there, but we’re already using it so I continued to use it here.

Now let’s get to using it. We’ll need a page for that.

<%@ Page Language="C#" AutoEventWireup="true"  CodeFile="Default.aspx.cs" Inherits="_Default" %>
<%@ Register src="DoAfterPostback.ascx" tagname="DoAfterPostback" tagprefix="uc1" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
    <script type="text/javascript" src="jquery.js"></script>
    <script type="text/javascript">
        function showMsg(s) {
            alert(s);
        }
    </script>
</head>
<body>
    <form id="form1" runat="server">
        <asp:ScriptManager ID="ScriptManager1" runat="server">
        </asp:ScriptManager>
        <div>
            <asp:UpdatePanel ID="UpdatePanel1" runat="server">
                <ContentTemplate>
                    <uc1:DoAfterPostback ID="DoAfterPostback1" runat="server" />
                    <asp:TextBox ID="TextBox1" runat="server" />
                    <asp:Button ID="Button1" runat="server"
                        Text    ="Button"
                        OnClick ="ButtonClicked" /><br />
                    <asp:Label ID="Label1" runat="server"
                        Text    ="Label" />
                </ContentTemplate>
            </asp:UpdatePanel>
        </div>
    </form>
</body>
</html>

We have a textbox, button and a label inside an UpdatePanel. We also have our user control in there. This will let the hidden field value change on partial postback and the new value to show up in our event handler. In addition, there is a trivial JavaScript function on the page for us to call after the postback:showMsg . Technically we could just throw the alert right in our control, but this more closely mimics how we’re going to do for real.

Finally we need some code on the server side to put some JS in our hidden field.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

public partial class _Default : System.Web.UI.Page
{
    protected void ButtonClicked(object sender, EventArgs e)
    {
        var s = TextBox1.Text;
        if (string.IsNullOrEmpty(s)) return;

        Label1.Text = string.Format("The user says {0}.", s);
        DoAfterPostback1.DoAfterPostbackJavaScript = "showMsg('" + s + "');";
    }
}

That should be it. Now we can enter text, hit the button and see both our server side processing take place and the client side JavaScript execute after the postback as completed.

Written by mark in: Web Development | Tags: , , , ,

7 Comments »

  • Thanks for the post. This was exactly what I needed. Because I think a rather useful application of this code would be to set a save button’s text to save, and then back to whatever it was before, I created a function to return the javascript needed and thought I’d post it here.

    Thanks!

    ///
    /// Used to change the text of a button to saved, and then back to whatever it was before a few seconds later
    ///
    ///
    ///
    public string GetUpdateSavedButtonJavaScript(string buttonClientId)
    {
    return string.Format(@”
    var saveButton = $(‘[id$={0}]‘);
    var saveTxtValue = saveButton.attr(‘value’);
    saveButton.attr(‘value’,'Saved!’)
    setTimeout(function() {{ saveButton.attr(‘value’,saveTxtValue) }}, 2000);”, buttonClientId);
    }

    Comment | July 2, 2009
  • @Daryl I’m glad it was useful. I would consider putting that JavaScript in a function that remains client side, then only create the invocation of that function dynamically. You could even get really fancy and do a count down timer on the button, similar to installing FireFox plugins; “Saved (2)”, “Saved (1)”, “Foo Button”.

    Comment | July 2, 2009
  • paul

    This solution worked great for me in this simple example. Solved my issue thanks!

    However I converted it to a ASP.NET server control so I can use it in many places and have placed inside a control library and now think that part of the script needs changing.

    The line in the Page_Load event:

    $(‘[id$=_DoAfterPostbackJavaScriptHiddenField]‘).each(doPostbackJS);

    I’m not 100% sure what the [id$=_DoAfterPostbackJavaScriptHiddenField] does. Im guessing its extracting the correct hiddenfield by its id. But what does id$=_ mean exactly or if this is use in conjunction with jquery (which is included and working in the sample youve shown.

    Help appriciated. Thanks

    Comment | January 20, 2010
  • @paul That is a jQuery selector that finds all elements that have an attribute ‘id’ that ends with ‘_DoAfterPostbackJavaScriptHiddenField’. See http://docs.jquery.com/Selectors for some more details. It might need to change if the generated ID of the hidden field is different now that it’s in a server control.

    jQuery selectors are tricky at first, but once you get the hang of it, they start making more sense.

    Comment | January 20, 2010
  • paul

    Ok thanks, while waiting for a reply. I just figured out what they were. Not really used jQuery before. But now understand the basics.

    Thanks a lot. Will give it a go and let you know if i get it working.

    Comment | January 20, 2010
  • paul

    Got this working in a server control now. Ajusted the JQuery selector but wasnt the issue. My issue was that in my test app (as apposed to my main app) my server control was not inside an update panel. Hence the add_endRequest function was not able to execute. Figured it out eveutually.

    Thanks a lot.

    Comment | January 21, 2010
  • @paul Good news! Firebug should be able to point that type of stuff out pretty quickly.

    Comment | January 21, 2010

RSS feed for comments on this post. TrackBack URL

Leave a comment

Powered by WordPress | Kredit | TheBuckmaker