>
Blog
Book
Portfolio
Search

7/28/2008

20378 Views // 0 Comments // Not Rated

Replacing "HTML" Events With "AJAX" Events

Before I developed my client-centric model for creating ASP.NET pages, I handled everything in code-behind, especially any dynamic HTML. I really only used JavaScript for quick-and-dirty DOM updates; any concept of creating controls was implemented via creating .NET objects and programmatically adding them to the page, or at the very least calling RenderControl on them to get the HTML out.

For example, if I wanted to hook a click event on a dynamically-created image, the code would look like this:

Code Listing 1

  1. using System.Web.UI.WebControls;
  2. ...
  3. Image img = new Image();
  4. ...
  5. img.Attributes.Add("onclick", "SomeJavaScriptMethod();");
  6. ...

I know this is a bit "old-skool" but it still works well for creating dynamic content on a page when fired from, usually, the load event. A good example of this is when I need to build crazy tree controls when the nodes can be dragged around the screen (which has been happening a lot, lately).

However, from the load event onward, now-a-days I do everything client side, leveraging AJAX and JSON Web Services wherever possible. The problem I want to address today is what happens when I need to unhook and rehook these events?

Continuing with the tree example: I am currently working on an application that allows users to drag tree nodes into a div, which kicks off an AJAX animation and adds a row to a table. Once they drag a node over, it becomes "disabled" in the tree so that they can't drag it again. In order to implement this, I needed to unhook the client-side event handlers. Further, in the case where they remove the aforementioned row from the aforementioned table, the node lights up again.

Unhooking the event is easy enough, but ugly. Here's the line of JavaScript that accomplishes this:

Code Listing 2

  1. img.setAttribute('onclick', '');

So to avoid this, I really wanted to use the AJAX framework's nice $removeHandler call, which looks like this:

Code Listing 3

  1. $removeHandler(img, 'onclick', SomeJavaScriptMethod);

Now this won't work for several reasons. First all, "onclick" in an event handler, not an event. Secondly, "SomeJavaScriptMethod" is a loose JavaScript method, not a delegate. And finally, even if we did manage to find legit objects for these parameters, AJAX will throw an exception if $removeHandler is called for an event on a DOM element if it wasn't initially wired with $addHandler.

So to start, we have no choice but to "clear" the event in the first place, as shown above with setAttribute.

Let's keep going. The next step is to "rehook" the event when necessary. Here's where setAttribute fails for sure. Calling something like:

Code Listing 4

  1. img.setAttribute('onclick', 'SomeJavaScriptMethod();');

doesn't work! No error was thrown; I didn't even get the infamous yellow exclamation mark in the bottom left-hand corner of IE's status bar. And that's fine, because I am an ASP.NET AJAX developer, so I want to use $addHandler regardless! So to put it all together, here's a JavaScript method that unhooks standard HTML events, and wires them back up with via the AJAX framework:

Code Listing 5

  1. function UpdateTreeNodeDrag(IdOfSomeImageDOMElement, someVariable, isDraggable)
  2. {
  3. //initialization
  4. var img = $get(IdOfSomeImageDOMElement);
  5. var someOtherVariable = 'some amazing value';
  6. var args = new Array();
  7. args[0] = someVariable;
  8. args[1] = someOtherVariable;
  9. //attempt to unhook ajax event
  10. try
  11. {
  12. $removeHandler(img, 'click', ClickEventHandler);
  13. }
  14. catch (ex) {}
  15. //update properties
  16. if (isDraggable)
  17. {
  18. //hook ajax event
  19. img.className = 'TreeNodeEnabled';
  20. $addHandler(img, 'click', Function.createCallback(ClickEventHandler, args));
  21. }
  22. else
  23. {
  24. //unhook html event
  25. img.className = 'TreeNodeDisabled';
  26. img.setAttribute('onclick', '');
  27. }
  28. }
  29. function ClickEventHandler(e, args)
  30. {
  31. //e is the AJAX event arg we get for free
  32. var img = e.target;
  33. //args is an example of a context variable
  34. img.src = args[0];
  35. }

Some bullets:

  • The event handler is just there for reference, showing the powerful ways you can use AJAX to hook up delegates that take (via a JavaScript array) any number of arguments to be passed to your event handler, as well as the magical "e" argument.
  • The try...catch construct will swallow the AJAX exception that's thrown if you try to remove a handler that wasn't added via $addHandler.  This is harmless, as no other exceptions will be thrown here, and it'll only blow up the first time the method is called.*
  • Subsequent calls to img.setAttribute('onclick', '') will have no effect.
  • Notice that in the "unhook html event" block, we pass 'onclick' since that is the name of the HTML attribute in the page's rendered markup.  However, when hooking the AJAX event, we use 'click' since that's technically the name of the event.
  • This was all tested and confirmed using IE 7 and ASP.NET AJAX

That's it! With this technique, you can implement client-side events using which ever method (ASP.NET on the server or AJAX on the client) suite your requirements best. But it's always coolest when the two can be intermixed to work together!

Have fun!

* I totally know that using exceptions for anything other than error reporting is dog crap. I would never use them for logic flow or anything like that. However, I'm sure that one little try...catch in JAVASCRIPT that has only a single line of code in it pertaining to something that can't even be tested for (as far as I can tell, there's no collection of attached events on a DOM element) is not all that bad.

No Tags

No Files

No Thoughts

Your Thoughts?

You need to login with Twitter to share a Thought on this post.


Loading...