Tuesday, May 18, 2010

Unobtrusive JavaScript and jQuery

What is Unobtrusive JavaScript?
jQuery was originally designed to follow the concept of Unobtrusive JavaScript. This philosophy of web page design considers any JavaScript expressions or statements embedded in the <body> of HTML pages, either as attributes of HTML elements or in script blocks placed within the body of the page, to be incorrect.

After reading this, I’m sure you’re nodding your head and thinking, “YES! that’s excellent...but wait, how do we link any JavaScript behavior to the elements that initiate that behavior?” The simple answer to this is somewhat a purest response - put all of your javascript in the head section of your page and then register all of your element behavior when the page loads. A simple before and after example is shown below:

Why would you want to do this in the first place? There are several reasons why this is a good approach to take. Firstly, it is much cleaner - you don’t have script elements scattered throughout your page. Secondly, it allows you to gracefully handle browsers that have disabled JavaScript. Lastly, it is much more stable - all behavior is registered after a given element is determined to exist within the page.

The cost of such an approach? It requires more code be written for one. But most importantly, it requires that each developer be disciplined enough to follow this approach as well as employ good coding practices to client-side script.

Introducing jQuery

The basis of jQuery selection is founded on a concept originally defined with the introduction of CSS known as selectors. A selector provides a way of concisely locating an element within a page’s DOM.
For example, the CSS selector

td a

refers to the group of all links (anchor tags - <a> elements) that are nested inside a table cell <td> element.

jQuery makes use of this same concept and then some. It supports the selector logic that is commonly supported by all major current browsers as well as more powerful ones not yet fully supported by most browsers - from the CSS 3 specification. The jQuery site provides a nice list of selectors that can be used at the following address - http://api.jquery.com/category/selectors/. An example selection by jQuery is done like so

jQuery(selector)

or

$(selector)

So in order to select the same anchor tag group as explained earlier (using the $ abbreviated alias reference used in our second example) our code would like like

$(“td a”)

The $() function returns an object that contains an array of the DOM elements that match our criteria. This jQuery wrapper object provides many useful predefined methods that can act upon this array of elements.

One very useful feature of many of the methods provided by the wrapper object is that they support method chaining. If you’re not familiar with method chaining, it is when one method’s return value can then be manipulated by the next method in the chain - much like how an assembly line works. To make this concept a little more concrete look at the following

$(“div”).methodA().methodB().methodC();

How this is interpreted is that the $(“div”) selects all <div> elements within the DOM and wraps them in our jQuery object. This object is then sent to the methodA() method which modifies the list of DOM elements. These modified elements are then sent to the methodB() method where they are modified further and so forth. This is a slight simplification, of course, but it captures the underlying concept. Because these methods work on the entire array of selected elements, there is never a need to iterate over each of the elements, this is done implicitly for us!

Adding Behavior to the Page Once the Document Structure has been Loaded and Parsed

To avoid having to wait for all resources to load into the browser as what happens with the document.onLoad() function, we utilize a jQuery utility that executes a function as soon as the document structure has been loaded and parsed by the browser, but prior to any other resources (images in particular) have been fully loaded. This helps to prevent pages that load very slowly from having a jarring effect on the user by changing behavior once all resources have completed downloading. This is accomplished via the jQuery document ready handler -
$(document).ready(function() {
  // function logic to add behavior, etc.
});
The short hand notation for this - $(function() { /* function logic */ }); performs the exact same but is more concise in its syntax. An added benefit of using the document ready handler is that you can call it multiple times within the page and each handler will be executed in the order it appears in the rendered page as soon as the DOM is ready to be manipulated (this is in vast contrast to the document.onLoad() function which allows only one call per page).

Extending jQuery to Provide Custom Behavior

jQuery was designed specifically to include only the most utilized functions as its core library but allow any developer to easily extend its behavior.
$.fn.myfunc = function() {
    return this.each(function() {
        // perform custom behavior logic
    });
}
This example shows how simple it is to extend jQuery to include new behavior while still working perfectly in concert with other jQuery functions. To briefly explain what is going on, the $.fn.myfunc defines a new extension wrapper called myfunc. Inside the new function we call the jQuery function each which iterates over the current DOM element and returns the results as a wrapped collection and so will fit seamlessly into any other chain of jQuery function calls. The reference to this within the function is a pointer to the specific DOM element for the current iteration.

This function would be used by first selecting your DOM context using the jQuery selector syntax just discussed and then chaining our function to this selection (and chaining further method calls after our function if need be) such as the following:

$(“form#ccform input”).myfunc();

As you can imagine, this is a very powerful extension architecture and requires only a small amount of scaffolding code in order to create new behavior.

Creating DOM Elements

Although, I’m not entirely fond of this idea, the $() function allows you to dynamically create and add arbitrary HTML elements by passing a valid HTML string as its parameter.

Coming up to Speed with jQuery

I’m an avid reader of anything that relates to technology - web, programming, algorithmic, AI, investing... The only limiter for what interests me is the amount of time I have that I can focus on any one thing at a time. Recently I picked up a book on the “new” ASP.Net MVC framework - ASP.NET MVC in Action by Palermo, Scheirman and Bogard. Although this book was written by very knowledgeable authors who truly understood their domain, I ended the book feeling that it was very disorganized and really didn’t pertain to ASP.Net MVC much at all. Most of the book was advertising the MvcContrib (which the authors created) and the CodeCampServer project. Much of the discussion was spent on describing how they weren’t going to explain the “nitty-gritty” but ended up not really explaining anything. Don’t think I’m being ungrateful for the contents of the book, it’s just that its benefit ended up being vastly different than what I had originally picked it up in the hopes of discovering. I’m sure at this point you’re wondering how this has anything to do with jQuery and that’d be a fair concern. What’s interesting about the MVC framework created by Microsoft is that they bundle in jQuery. This truly came as a surprise to me when I first downloaded it simply for the fact that Microsoft is not well known for using anything that was not built in-house - most likely due to the penchant for everyone to sue them. When I first discovered this I was intrigued and so I started my journey to see what jQuery had to offer. 

Over the past several weeks I’ve been working on a project that utilizes the ASP.NET MVC 2 framework for its underlying web architecture. Since I knew that jQuery was already “compatible” with MVC I decided to see what it could do. I started to search ad hoc on the web for different packages to determine how healthy the project was and how vibrant its community participation was. Overall, it’s has a very solid  following. At this point I’ve already integrated several of the core plugin packages such as jQuery UI (which itself has several UI components included within it as well as an absolutely great theming utility on its website) and jqGrid (open source version). These plugins work great out of the box, but as with anything that you start to use, you’ll eventually get to the point where you need a little more control over everything. This brings me to the purpose of this (now long-winded) blog. Over the next several posts I hope to cover in a decent amount of depth how jQuery works and provide a running example (with working site code) to show the items in action. I’m still new to blogging, so if my style does not work well in this media, please give feedback so that I can improve and provide the most value to you. 

Monday, May 3, 2010

Adding CSS styles to ASP.NET MVC 2 Drop Down List Binding

Just read a pretty nice article describing how to perform the equivalent of data binding in MVC 2 with a drop down list at - http://www.nickriggs.com/posts/rendering-and-binding-drop-down-lists-using-asp-net-mvc-2-editorfor/

The only thing that I found myself needing to add was a per instance css class/classes. The Html.EditorFor() method has an additionalViewData parameter that can be used for this to pass the required css class to the underlying partial view control. In this example I'm assuming you've read the article mentioned above and so I won't explain the meaning of the files and their relationship.

As a side note, I also followed the directions found on codingfreak to enable the much nicer syntax highlighting library...and in case you're wanting to add this to your blog as well, I'll pass on my stupidity so hopefully I'll save you the same...the "Preview" provided by blogger.com does not format it correctly, you actually have to post the blog for it to take the proper form.

The first item is to add the @css entry as the second parameter to the EditorFor method.

// Index.aspx<br />...<br />  <div><label id="lblGender">Gender</label><br />     <br />  </div>
...<br />

Now to consume this properly, all you have to do is utilize a mixture of the htmlAttributes anonymous object in the Html.DropDownListFor method along with the value you set in the Html.EditorFor additionViewData anonymous object as shown below.

<br /><%= Html.EditorFor(m => m.GenderList, new { @css = "search_gender_text" }) %>

It's not rocket science, but hopefully it might save you a couple of minutes of research and tinkering.


Friday, April 23, 2010

Resharper tidbit

Great post on an issue with Resharper that I've grumbled about for a really long time, but had done nothing about. Keeping the "Code Cleanup" from automatically placing Regions around code during cleanup.

http://stevesmithblog.com/blog/prevent-resharper-from-adding-regions/

Monday, April 19, 2010

Setting up a new ASP.NET MVC project NUnit testing template

In this blog, I'm going to outline the steps necessary to setup a skeleton project that can be used by the ASP.NET MVC 2 framework that uses NUnit as the testing framework by default. These steps were originally described for MVC version 1 in the book by Palermo - ASP.NET MVC in Action.

  • Download and install the MVC2 framework from http://www.asp.net/downloads/
  • Download and install the latest NUnit framework from http://www.nunit.org/index.php?p=download
  • Download and uncompress the Rhino Mock framework from http://www.ayende.com/projects/rhino-mocks.aspx
  • Download and uncompress the Windsor 2.1 framework from http://www.castleproject.org/castle/download.html
  • Open Visual Studio and create a new ASP.NET MVC 2 Web Application Project within Visual Studio 2008 (change the names to suit your template, location does not matter since we'll be exporting as a template)
  • Change the name of the Test project to suit your needs and make sure that the Visual Studio Unit Test test framework is selected.
  • In the Test project remove the reference to Microsoft.VisualStudio.QualityTools.UnitTestFramework and add references to the project for the following dlls and verify that all of their properties are set to Copy Local (make sure to either add these to the GAC or a semi-permanent location or network share or you will end up breaking the template if that directory changes). I also, decided that in order to be able to immediately compile when a new project is created with this template, I removed the reference to the base project from the test project and removed all code that referenced the VS Unit Testing framework.
    1. Castle.Core
    2. Castle.DynamicProxy2
    3. Castle.MicroKernel
    4. Castle.Windsor
    5. nunit.framework
    6. Rhino.Mocks
  • Save all changes and go to File > Export Template
  • Select the Project template option and verify that the MvcApplication.NUnitTests is selected as the project from which to create a template
  • Click Next
  • Change the template name to MvcApplication.NUnitTests.cs
  • Change the template description to something meaningful, such as - ASP.NET MVC Web Application NUnit project template
  • Keep both the Automatically import the template into Visual Studio as well as the Display an explorer window on the output files folder options selected - the end result should be a single zip file that will be displayed when in explorer when we're finished.
  • Click Finish and Windows Explorer popups up with the output zip file (it should default to \Visual Studio 2008\My Exported Templates). Copy this file to C:\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\IDE\ProjectTemplates\CSharp\Test (assuming you're running the 64-bit version of Windows 7, adjust this path according to your environment)
  • Close all open instances of Visual Studio
  • Open the Visual Studio 2008 Command Prompt (as Administrator) and run the following command to install the template (the command prompt can be found under Start > All Programs > Microsoft Visual Studio 2008 > Visual Studio Tools > Visual Studio 2008 Command Prompt) - Note: this may take a couple of minutes depending on your computer and templates available
    • devenv /installvstemplates
  • Close the command prompt
  • Create a new file with the following contents (editing the paths to match your environment)
Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\9.0\MVC2\TestProjectTemplates\NUnit]
"Template"="MvcApplication.NUnitTests.cs.zip"
"Path"="CSharp\\Test"
"TestFrameworkName"="NUnit Test"
"AdditionalInfo"="http://www.nunit.org/index.php?p=home"
"Package"=""
  • Choose a file name (such as - NUnit Test template Example.reg) and save the file to a location that you can navigate to easily
  • Open a normal command prompt (with adminstrative priviledges) and navigate to where you saved the file created in the previous step
  • Run the following - regedit.exe /s "[path to file]\NUnit Test template Example.reg"
  • Open Visual Studio and Create a new MVC project with the new template for NUnit 

Setting up a Remote Desktop Connection from Windows to Mac

This issue has been plaguing me for a while now. I have two computers, two monitors, two keyboards, two mice and a very cool antique desk that is big enough for one of each (except, of course, for the two monitors which are staying). The Screen Sharing technology utilized by OS X is very slick and I use it between my laptop and desktop all of the time, but how do you remote desktop from a PC to a Mac? I'm a little embarrassed that this didn't occur to me earlier since I already knew that VNC was the underlying technology used by OS X. That being said, I finally came across a mac forum post that reminded me of this fact.

The Problem
I work in Windows, but I have all of my music and other "good" stuff on the Mac, so what to do?

My two options to clear the clutter on my desktop are the following:
  1. Plug both monitors into the Mac and remote desktop to the PC
  2. Plug both monitors into the PC and remote desktop to the Mac
Option one works, and quite well in most circumstances using the Microsoft Remote Desktop Connection Client, but it is plagued by a few oddities in its behavior. The two most annoying of these are that I can't use both monitors for the PC (i.e., can't spread the remote desktop to fill both monitors) and certain things, such as video playback, are really ugly over the remote desktop client.

So option two it is! I've been searching for solutions to this problem for a while now and think I've finally come across one that is acceptable. The following details the procedure I followed that appears to work in my environment. This setup, of course, is dependent upon access limitations of your specific environment - sub-nets, VPNs (virtual private networks), etc.

Download and install UltraVNC (freeware)
    1. http://www.uvnc.com/download/index.html

    2. Select the latest version for download (1.0.8.2 as of this writing)


    3. On the next page I selected the full version to download since I haven't previously installed any version of VNC on this PC - 1.0.8.2 Full


    4. On the final page I selected the 64-bit version of the full download - X64 1.0.8.2 Full

    5. I saved the file to my desktop and then ran it like a normal installer





    6. I clicked through the wizard, accepted the license agreement, etc. The only modification I made from the default values provided for the installation was in what was finally installed. To keep as much processing power as possible, I like minimal services running on my computer and so I only wanted the minimal installation for my setup. As one of the last steps, I was given the option of what to install to which I selected the UltraVNC Viewer Only option.

    7. Click Next three more times and then Install & the installer goes through its process.


    Enabling Mac to Accept Incoming VNC Connection

    First, you must enable remote administration within OS X

    1. Select the Apple menu in the top left of your menu bar. Select System Preferences... on the menu that drops down.


    2. On the Internet & Wireless (third) row of items in the System Preferences dialog that pops up select the folder that is titled Sharing



    3. In the Sharing dialog window, make sure that the Screen Sharing option is selected in the left section of the window.



    4. Tighten security so that it is not open to everyone. First select the "Computer Settings..." button in the upper right area of the dialog box. In the drop down window that appears, check the box that says "VNC viewers may control screen with password" and then enter a password that you will remember.



    5. Limit the users that can access your computer in the bottom right section that starts with the "Allow access for:" label.



    Determining the IP of your Mac

    1. You can discover the current IP assigned to your Mac by again selecting System Preferences from the Apple menu and then selecting Network



    2. Select the connection that is active in the list on the left of the dialog window (in my case it is the AirPort connection).



    3. When this is selected, the content area (the right side of the window) will update with the current state of that connection. Next to the Status label you should see the word Connected and then below that should be listed the current IP assigned to your Mac. This IP address will be used later when connecting from your PC.



    Connecting to your Mac

    You will start up the VNC viewer client as you normally would any other application. I plan to use this on a daily basis, so I placed it as a "pinned" shortcut on my Start menu (you pin any application to the Start menu by right-clicking on the .exe and selecting the Pin to Start Menu option).

    The option dialog box that displays next allows you to configure how the connection will behave. Since mine will be going over very strong wireless connection, there should be little to no lag and so I've set the highest settings for connecting to the remote computer. You'll need to configure this based on your specific network conditions. However, the "auto" selection for quick options works really well for most situations.

    I clicked the "Save connection settings as default" since I will be using this connection over and over. I clicked Connect and was immediately prompted for a password (remember the password you set on the Mac machine to allow users to control that box?). 
     

    I entered the password and viola!!