Thursday, June 2, 2005

Multiple Onclick JavaScript Events on a Single Control

[This was originally posted at http://timstall.dotnetdevelopersjournal.com/multiple_onclick_javascript_events_on_a_single_control.htm]

Change History: This post was updated on July 5, 2005. See Update at bottom.

You can't add two identical events to the same Html control. For example, if you have a button with an onclick event, and you add another onclick at the server, the second event will overwrite the first. This becomes a problem if you need to add an event to some variable control, but you don't know what events that control already has. However, .Net provides a way to handle this.

We can:

  1. See if the variable html control already has an onclick event.
  2. If it does, then dynamically register a new script that calls both the original onclick script as well as the new script.
  3. Replace the variable control's onclick value with that new script.

The following code snippets this. This first block shows a simple JavaScript (with a parameter) being called by a button's onclick event.

function DoStuff1(var1) {
    alert('1: ' + var1);
}

...

...

This snippet shows the server code to check if an onclick event already exists, and add a new wrapper if needed. Note that it persists the onclick values in viewstate to ensure that the wrapper function doesn't wrap itself upon postback. For example, if the first onclick event called DoStuff1(), and we wanted to dynamically add a new onclick function DoStuff2(), we could create a wrapper function Wrapper1() that called both functions, and was called from the onclick. Wrapper1() becomes the new value of the button's onclick.

private void Page_Load(object sender, System.EventArgs e)
{
    string s = this.Button1.Attributes["onclick"];
    if (!Page.IsPostBack)
        OriginalJSFunction = s;
    if (s == null)
        this.Button1.Attributes.Add("onclick","DoStuff2()");
    else
    {
        if (!Page.IsClientScriptBlockRegistered("JS1"))
            Page.RegisterClientScriptBlock("JS1",GetJS(OriginalJSFunction));
        this.Button1.Attributes.Add("onclick","Wrapper1()");
    }
}

private string OriginalJSFunction
{
    get
    {
        object o = ViewState["OriginalJSFunction"];
        if (o == null)
            return "";
        else
            return o.ToString();
    }
    set
    {
        ViewState["OriginalJSFunction"] = value;
    }
}

private string GetJS(string strOriginalFn) //will handle initial JS with params
{
    System.Text.StringBuilder sb = new System.Text.StringBuilder();
    sb.Append(@"
       
    ");

    return sb.ToString();
}

 While this approach is tedious, it lets you dynamically add an event to a control without overwriting that control's existing event. This is useful when making your own custom controls that integrate with existing Html controls already on the page.

UPDATE July 5, 2005

Since writing this post, I've come across a cleaner technique. You can run multiple JavaScripts simply by listing them in the onclick event:

 id="Button1" onclick="DoStuff1('Hello1');Method2();Method3()"

Therefore we can simplify our codebehind. This has two main changes: (1) It modifies OriginalJSFunction to append the ";" to the end of a non-function, (2) It then always adds an onclick method, as opposed to checking if there already exists an onclick method.

private void Page_Load(object sender, System.EventArgs e)
{
  string s = this.Button1.Attributes["onclick"];
  if (!Page.IsPostBack)
    OriginalJSFunction = s;
   
  this.Button1.Attributes.Add("onclick",OriginalJSFunction + ";DoStuff2()");
}

private string OriginalJSFunction
{
  get
  {
    object o = ViewState["OriginalJSFunction"];
    if (o == null)
      return "";
    else
      return o.ToString() + ";";
  }
  set
  {
    ViewState["OriginalJSFunction"] = value;
  }
}

No comments:

Post a Comment