Friday, November 27, 2009

Use Sys.Application.add_load instead of $(document).ready()

I use the Telerik ASP.Net control suite in my application as well as jQuery.  Everything had been working just fine.  It is very common that I would write code that needed to be run once a page was loaded and I was using the jQuery ready() function like this:

$(document).ready(function() {
    ... // My initialization code here 
});

This was working great for  a while.  That is until I decided that I wanted to write some script that interacts with the Telerik RadDatePicker.  I had a RadDatePicker on my page and at one point I wanted to write some code that would read the selected date of the RadDatePicker so I was using the following code:

$find('<%= MyControl.ClientID %>').get_selectedDate();

I do my development in Firefox and this was working fine.  But when I tried to test the page in Internet Explorer, the $find method was returning null.  I searched around trying to figure out what was going on.  I finally discovered that I needed to use the Sys.Application.add_load method like this:

function initDates() {
    $find('<%= MyControl.ClientID %>').get_selectedDate(); 
}

Sys.Application.add_load(initDates);

While this technically worked, in my application I use UpdatePanel's and I was already catching the pageLoad event and firing it through jQuery as such:

function pageLoad() {
        $(document).trigger("pageLoad");
}

I do this so that I can write code in my UserControl's  like this:

$(document).one("pageLoad", function() {
    .. // My UserControl initialization code.
});

So since I already had a framework for hooking into the client-side page load event, I didn't actually need to use the Sys.Application.add_load method.  I hope this helps someone.  I had a very frustrating time dealing with this annoying problem.

To summarize, you can't use the onload event to interact ASP.NET AJAX client-side Components because they are not initialized at that point.  Now why it was working in Firefox is still a mystery to me, but I would still avoid it.

For a more detailed description about these two methods of running code at startup, check out this article.

Friday, November 20, 2009

Silverlight: Specify Control To Load Via Launch Parameter

Shortly after integrating a Silverlight control into my application, I discovered that I would want to be able to run more than one control from the same Silverlight application.  My framework that I developed consisted of the following:
  1. A javascript function to launch the Silverlight control.
  2. A modification of the App class in my Silverlight application.
The first thing I had to do was modify the javascript that launched the Silverlight application.  I had to include a param to the <object> control.  The name of the param is “InitParams”.  This is the value that gets passed to the Silverlight App class (this is a Silverlight parameter and you seperate multiple parameters with the ',').  I simply set it to a value that contains “Page=MyControlClassToLaunch”.

"<param name='InitParams' 
value='Page=Namespace.ControlClass' />";

After changing the <object> tag to have a parameter specifying the control I wanted to load, I needed to modify the App class to make sure that it loaded the control.

To do this, I had to override the Startup event.  In that method, I check the InitParams to get the Page param out of it.  Once I had the Page to load, I had to use reflection to get all the types from the Silverlight assembly.  I then iterate over all the types to find the type that matches the type passed in the Page param.

Once we have the Type of the control to load, we use the Activator.CreateInstance method to instantiate the control.

Now that we have the control instantiated, all we need to do is set the RootVisual property of the App class and we have successfully used an <object> tag param to tell the App which control we would like to launch.
 
private void Application_Startup(object sender, 
StartupEventArgs e) {
  if (e.InitParams.ContainsKey("Page")) {
      string page = e.InitParams["Page"];
      Type[] types = Assembly.GetExecutingAssembly().GetTypes();
      foreach (Type type in types) {
          if (type.FullName == page) {
              RootVisual = 
(UIElement) Activator.CreateInstance(type);
              return;
          }
      }
  }
  RootVisual = new DefaultPage();
}

It is now possible to have many Silverlight controls all located within a single application and launch different ones from javascript by easily setting a parameter on the tag.

Thursday, November 19, 2009

JavaScript Testing Frameworks

While searching for a framework to use in my testing of JavaScript, I discovered that there is quite a large list of frameworks out there.  Before choosing, I decided to make a list.   I will be doing further investigation as to which ones are good and in what situations they should be used, but that is a post for another time.  For now, just the list:
 
Testing Frameworks
BrowserUnit -
Celerity - A Ruby wrapper around HtmlUnit.
crosscheck -
doh.robot - doh.robot, dojo.robot, and dijit.robot (might be the same as DOH)
DOH -
envyjs -
FireUnit - A plug-in for FireFox.
HtmlUnit -
J3Unit -
jsspec -
JSNUnit - JsUnit on .Net
JSpec -
JSTest -
JsTestDriver - A framework developed by Google
Jsunit -
JsUnitTest -
jsUnity - Not for testing browser code, only pure javascript.
QUnit - Browser based unit testing framework from the makers of jQuery.
RhinoUnit -  Ant based.
Schnell - A Ruby wrapper around HtmlUnit.
ScrewUnit -
script.aculo.us unit testing -
SimpleTest from MochiKit -
Test.More 
Test.Simple
TestCase
Testrunner - Don't have much information about this one.
TestSwarm - A framework being developed for jQuery for cross browser support.
WatiN - Appears to be an attempt to bring Watir to .Net
YUI Test - A testing framework from Yahoo!.

Mocking Frameworks
Jack -
JSMock -
MockMe for JavaScript -
QMock -

Some Useful Links:
Other unit test list
Run JavaScript from Watir
Test Driven AJAX
TDD and Javascript with JsMock
Test Driven Javascript
TDD and Javascript with JsMock