views:

84

answers:

3

I am trying to replace the JavaScript onclick event handler in ASP.NET that is added to a button control when using validation controls. This is what is output into the HTML from ASP.NET in this scenario:

<input type="image" name="ibSubmit1" id="ibSubmit1" src="button-green-submit.gif" onclick="showProgress1();WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(&quot;ibSubmit1&quot;, &quot;&quot;, true, &quot;Group1&quot;, &quot;&quot;, false, false))" style="border-width:0px;" />

I have looked pretty estensively, and unfortunately there doesn't seem to be a way to modify the function server side before it is injected into the page.

Since I am developing a control and desire it to be non-invasive and self contained, and I am interested in obtaining the validationGroup parameter of the WebForm_PostBackOptions object, it seems that the easiest solution would be to use JavaScript to replace the WebForm_DoPostBackWithOptions function name with my custom wrapper function and leave all of the rest of the parameter information intact - then I can extract the information I am interested in, call my custom functions, and then forward the call on to WebForm_DoPostBackWithOptions.

NOTE: I am using jQuery to build my custom function, so if there is an easier way to do this with jQuery it is an option I will consider.

Here is the code I tried to replace the onclick event handler (not working):

    $('[onclick*=WebForm_DoPostBackWithOptions]').each(function() {
        var txt = this.onclick;
        txt = txt + '';
        txt = txt.replace('WebForm_DoPostBackWithOptions','ml_DoPostBackWithOptions');
        this.onclick = eval(txt);
    });

Using alert(), I verified that the text is being changed correctly, however whether or not I use the eval() function, the onclick handler doesn't seem to recognize it as JavaScript.

I thought of using a regular expression to get the validationGroup value, but this seems like it will be far more elegant and flexible if I can get it working...

Note: If there is a way for my control to interrogate the page it is on to find all of the buttons that will post back (regardless of what type of buttons they are) so I can retrieve the property server-side, this is also something I will consider.

A: 
Brian
+1  A: 

The attribute value is wrapped in a function when the HTML is parsed, so it would be tricky to get the original string back. You can get the string representation of the function, but then you would have to parse out the code inside the function.

Why not just redefine the function that is called? Put this at the end of the page:

<script type="text/javascript">

(function(){

  // keep the original
  var previous = WebForm_DoPostBackWithOptions;

  WebForm_DoPostBackWithOptions = function(options) {
    // do what you want with the options here
    // then call the original
    previous(options);
  }

})();

</script>
Guffa
The issue with this is that ASP.NET automatically generates the function. I just need to figure out a way to intercept the 4th parameter - the validationGroup because I need to know which group the button belongs to.While it is possible in .NET to determine this on the server, since I creating a control that technically is unaware of other controls and I have no way of knowing what buttons on the form will have this event, it seems easier to just handle this on the client. My control doesn't have any server side functionality.
NightOwl888
@NightOwl888: The code above should do the same as your attempt to replace the function name, only it intercepts the call one step later. There is only one parameter to the call; the `WebForm_PostBackOptions` object, so you have to get the property from that object, just as you would have in your `ml_DoPostBackWithOptions` function.
Guffa
The issue with your code is that there already is a function named WebForm_DoPostBackWithOptions in a javascript file that is included with ASP.NET. If I use your code as is, I will get an error. That is why I am trying to sidestep the name of the function - it is easier to do that then to try to wrap the .js file and dynamically replace the contents of the function.I have converted the function to plain text by concatenating an empty string. I have figured out how to replace the function name. The only part I am stumped on is attaching my plain text back to the onclick event.
NightOwl888
@NightOwl888: I think that you have misunderstood the code completely, it doesn't try to change the contents of the js file. The code *relies* on the fact that the function name is already defined. It redefines it to a wrapper where you can put your code, and then calls the original function.
Guffa
Doh! I stand corrected. This method will come in handy both now and in the future, and is definitely cleaner than what I was trying to do.
NightOwl888
I thought you had it working, but...I tried the code exactly as it is, and it partially worked. I put an alert where you commented "do what you want" and it was called and confirmed I could get the value I need. However, the call to previous(options) did not fire the original function. Any ideas?
NightOwl888
I stand corrected again...I was testing something and commented out the event handler of the button. After it was reattached, everything worked fine. I think this will work, but I am still investigating injecting function calls from the server.
NightOwl888
A: 

If you are just trying to insert functionality to the click event, then you can use the click() function of jQuery. It adds the function call to the start of the click event and then allows the default behaviour to occur, in this case a form submission:

 $(function() {
    $('[onclick*=WebForm_DoPostBackWithOptions]').click(function(event) {  

        //call your custom functions here and then do nothing, the 
        //default click event will still occur. If you don't want it to
        //propagate, call event.preventDefault();

        var txt = this.onclick;
        txt = txt + '';
        txt = txt.replace('WebForm_DoPostBackWithOptions','ml_DoPostBackWithOptions');
        setTimeout(txt,0);

        //event.preventDefault();  
        //or
        //event.stopPropagation();  
    });
 });

Note that in the example that you have given, showProgress1(); will get called twice.

Daniel Dyson
I am trying to insert functionality in the click event also, but that is the easy part. The difficult part is that I am trying to intercept the validationGroup parameter - the 4th parameter of the WebForm_PostBackOptions. Unfortunately, on the client side the only place the validationGroup exists is in this function call.If I could just replace the function name with a custom function name and reattach the event, then I would have full access to the object (parameter) including the validationGroup.
NightOwl888
BTW - I put an alert in showProgress1() and clicked the button - it only fired once. Could you explain why you think it would be called twice...if there is something wrong with the code I would like to try to fix it.
NightOwl888
My assumption was that after calling var txt = this.onclick;, txt would contain "showProgress1();WebForm_DoPostBackWithOptions(..." replacing WebForm_ etc with ml_DoPost etc would still leave showProgress() in the replacement script as well as in the original, which would get called after the replacement script. What does txt conatin after the inital assignment?
Daniel Dyson
The text contains both function names wrapped by a function called anonymous. You are correct, the text does contain the showProgress() function, and that was intentional. My assumption was that this.onclick = eval(txt); would overwrite the contents of onclick with the new function calls. However, upon placing an alert in my custom (ml_) function, it was never called, nor was there an error. I am pretty sure there is something wrong with the syntax for converting the text back to an actual function call that the javascript interpreter could execute.
NightOwl888
No, this.onclick = exal(txt); will not overwrite the function calls. The browser has an event model whereby the function calls are bound to (in this case) the click event, based on what is in the onclick attribute when the page is loaded. What you need to do is rebind the event to a different function, hence the use of the 'jQuery click(function(...' code in my answer. Also, eval executes immediately, so in your example where you are calling the 'jQuery each(function)...', the txt in eval is being executed immediately on each loop of the each, rather than when the button is clicked
Daniel Dyson