My 7 jQuery Articles on Script Junkie








Recently a brand new Microsoft website has been launched called Script Junkie that focuses on JavaScript, HTML, CSS, and moreā€¦
<ul><li>Script Junkie Website </li><li>Twitter (@script_junkie) </li><li>Twitter List of Authors (@script_junkie/script-junkie-authors) </li><li>Script Junkie RSS Feed</li></ul>Over the past 7 months or so Iā€™ve written 7 articles that are now available on Script Junkie. I was honored to write these articles for the launch of the website. I hope this clues you into why the blog posts on this site have been lacking.
<ol><li>Six Things Every jQuery Developer Should Know</li><li>How to Debug Your jQuery Code</li><li>History and Back Button Support</li><li>Intro to Error Handling in Ajax Apps</li><li>Custom jQuery Events and Selector Filters</li><li>How to Create Your Own jQuery Plugin</li><li>jQuery Test-Driven Development</li></ol>I am taking a break from writing for Script Junkie for a while. Our 3rd baby is due in August ;)
I hope you find the above articles helpful.

Read More »

Switching to the Strategy Pattern in JavaScript

A Typical Switch Statement Scenario

Recently Iā€™ve been working on some highly dynamic User Interfaces and at one point in the project I found my first reflex on a certain task to use a switch statement in JavaScript.

Now, my previous training in studying the Design Patterns has told me that the switch statement is bad. The design pattern drilled into me to resolve the switch statement is the the Strategy Pattern, however, Iā€™ve never used the Strategy Pattern in JavaScript before.

The following example is a simple demo application where I start with a switch statement and then refactor the code later in the blog post to use the Strategy Pattern.

A Simple Super Hero Demo Application

SuperHeroShadow

The sample application is a Super Hero creator. You provide a Super Hero name and then you select your Super Hero power. The power can be a variety of things ranging from Flying, Invisibility, to nothing at all. Some of the powers have additional questions (metadata) about that particular power.

Once the Super Hero is created, the application should build up a object with the appropriate power type and supporting metadata. For now, Iā€™m just outputting the object in the Firebug Lite console using console.dir().

First Pass at a Switch Statement Solution

Here is the above application written using a switch statement to build up the Power type and metadata. The solution is fairly simple in nature. I am utilizing the Revealing Module Pattern.

Note: You can view, run, and edit the following codeā€¦ http://jsfiddle.net/elijahmanor/KzAMX/

var superHeroModule = (function () {
var public = {};

public.init = function() {
$("input:radio[name='Power']").click(function() {
var selectedPower = this.value;

$("#powers .power").hide();
$("#powers ." + selectedPower).show();
});

$("#create").click(function() {
var superHero = public.scrapeSuperHero();
console.dir(superHero);
});
};

public.scrapeSuperHero = function() {
var superHero = {};

superHero.Name = $("#Name").val();
superHero.Power = public.scrapePower();

return superHero;
};

public.scrapePower = function() {
var power = {};

var selectedPower = $("input:radio[name='Power']:checked").val();
switch (selectedPower) {
case "Flying" :
power.type = "Flying";
power.speed = $("#flyingSpeed").val();
break;
case "Invisibility" :
power.type = "Invisibility";
break;
case "Strength" :
power.type = "Strength";
power.lift = $("#strengthLift").val();
power.strongerThan = $("#strengthStrongerThan").val();
break;
case "Vision" :
power.type = "Vision";
power.distance = $("#visionDistance").val();
power.seeInDark = $("#visionDark").is(":checked");
power.xrayVision = $("#visionXray").is(":checked");
break;
}

return power;
};

return public;
} ());

superHeroModule.init();

cooltext439925164

Pros of this Solution

  • Simple Implementation
  • All the code is in one place to handle building up the Super Hero power metadata

Cons of this Solution

For those of you aware of Bob Martinā€™s (@unclebobmartin) SOLID Principles, the ā€œOā€ represents the Open/Closed Principle which states thatā€¦

Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification

The switch solution violates the Open/Closed Principle in that every time a new Super Hero power is added to the list that the same piece of code will need to be modified. This is problematic in that new bugs can easily be introduced as new features are added or as defects are resolved.

Letā€™s look at a better way to solve the solution.

Refactoring Using the Strategy Pattern

A lof of the code will remain the same in the refactored solution. We mainly want to pull out the switch statement into something that is more maintainable and less error prone for future enhancment.

Note: You can view, run, and edit the following codeā€¦ http://jsfiddle.net/elijahmanor/K8CkZ/

var superHeroModule = (function () {
var public = {};

public.init = function() {
$("input:radio[name='Power']").click(function() {
var selectedPower = this.value;

$("#powers .power").hide();
$("#powers ." + selectedPower).show();
});

$("#create").click(function() {
var superHero = public.scrapeSuperHero();
console.dir(superHero);
});
};

public.scrapeSuperHero = function() {
var superHero = {};

superHero.Name = $("#Name").val();
superHero.Power = public.scrapePower();

return superHero;
};

public.scrapePower = function() {
var power = {};

var selectedPower = $("input:radio[name='Power']:checked").val();
var scrapePowerFunction = "public.scrapePower" + selectedPower;
power = eval(scrapePowerFunction)();

return power;
};

public.scrapePowerFlying = function() {
var power = {};

power.type = "Flying";
power.speed = $("#flyingSpeed").val();

return power;
};

public.scrapePowerInvisibility = function() {
var power = {};

power.type = "Invisibility";

return power;
};

public.scrapePowerStrength = function() {
var power = {};

power.type = "Strength";
power.lift = $("#strengthLift").val();
power.strongerThan = $("#strengthStrongerThan").val();

return power;
};

public.scrapePowerVision = function() {
var power = {};

power.type = "Vision";
power.distance = $("#visionDistance").val();
power.seeInDark = $("#visionDark").is(":checked");
power.xrayVision = $("#visionXray").is(":checked");

return power;
};

return public;
} ());

superHeroModule.init();

cooltext439925164

Pros of this Solution

  • Abides by the Open/Closed Principle by opening the code for extension, but closing it for modification.

Cons of this Solution

  • The solution is more complex than the previous switch statement implementation
  • You might have noticed the use of the eval function. Douglas Crockford labeled the eval function as a Bad Part of JavaScript for some very good reasons, however, in this case I think the benefits it brings in this situation outweighs the risks. With every hard and fast rule, there comes a place and time to examine the benefits and risks.

Conclusion

I found that separating the switch statement logic into the above Strategy Pattern has made my current project much more maintainable and less error prone when adding new features.

How have you addressed similar situation? Have you implemented a different solution to the switch statement problem? Please share with me, Iā€™d love to know!

Read More »

Couch Potato 1.1 Bookmarklet ā€“ Expand/Collapse

4146293_ac8f

I updated the Couch Potato bookmarklet to add the ability to expand and collapse the details of each document from the list page by clicking the ā€œ+ā€ to the left of the document key.

You can also click the ā€œExpand All Documentsā€ action located in the right navigation column.

The Bookmarklet

To use the bookmarklet, drag the following link to your bookmark/favorites list:

Ā» Couch Potato 1.1 Ā«

Read More »

Couch Potato Bookmarklet ā€“ Lazy Features for CouchDBā€™s Futon

The Problem

Weā€™ve been using CouchDB in our current project at work and Iā€™ve been using the CouchDB Futon manager more and more lately to create, edit, or delete documents.

FutonBeforeDropShadow

After a lot of test data gets into our document store, I end up needing to clear out the documents. I could Delete the whole database with a button, but Iā€™d rather not remove the CouchDB design documents defining custom views.

In order to delete documents from Futon, you have to manually drill down into each document and then click the delete button. I found this very monotonous, so I decided to make a bookmarklet to help me out some.

The Solution

So, I created the CouchDB Potato Bookmarklet (because Iā€™m lazy). The bookmarklet creates a new delete column and provides a ā€œDelete Documentsā€ link to delete all the checked documents. I also added a ā€œSelect All Documentsā€ which only selects non-design documents (so that I donā€™t accidentally delete a CouchDB view). These links can be found in the right navigation column under the ā€œRecent Databasesā€ section.

FutonAfterDropShadow

The Bookmarklet

To use the bookmarklet, drag the following link to your bookmark/favorites list:

Ā» Couch Potato Ā«

Then, when you're on a listing page in Futon, just click the bookmarklet.

Ideas for Future Development

Iā€™ve considered adding some more functionality to Couch Potato such as

  • Converting it into a GreaseMonkey script (Google Chrome & Firefox)
  • Add tooltips to the document rows showing the details of the stored document

Do you have any ideas youā€™d like to see?

Read More »

Opinionated ASP.NET MVC 2 Template Helpers

If you have used ASP.NET MVC any, then you are probably aware of the MVC Contrib project hosted on CodePlex. It is a helpful library that provides useful tools that ASP.NET MVC doesnā€™t give you out of the box.

Opinionated Input Builders

One of the pieces that I really like is the Opinionated Input Builders that Eric Hexter wrote. The builder allows you to provide one property at a time from your View Model and it will output the label, required indicator, the appropriate input control, and whatever else that it needs to display.

<% using (Html.BeginForm()) { %>

<%= Html.Input(m => m.FirstName) %>
<%= Html.Input(m => m.LastName) %>
<%= Html.Input(m => m.Email) %>





<% } %>

Ā 

MvcContribPicNik

ASP.NET MVC 2 EditorForModel

As it turns out, the ASP.NET MVC team took a similar approach when putting together the Template Helpers inĀ  ASP.NET MVC 2. I ended up switching to the Template Helpers.

<% Html.EnableClientValidation(); %>
<% using (Html.BeginForm()) { %>

<%= Html.EditorForModel() %>





<% } %>

With some CSS styling, the output of the EditorForModel is close to what the Opinionated Input Builder, but there are some problems as weā€™ll discuss in the next section.

Mvc2ModelPikNic

ASP.NET MVC 2 EditorFor

The problem is that I usually donā€™t want to display or edit my entire model. I often times have things in my View Model that I donā€™t particularly want to display.Ā  I want to rather manually choose which properties I want to display or edit.

<% Html.EnableClientValidation(); %>
<% using (Html.BeginForm()) { %>

<%= Html.EditorFor(m => m.FirstName) %>
<%= Html.EditorFor(m => m.LastName)%>
<%-- Purposely Not Show the Email ā€“%>





<% } %>

Using the above syntax doesnā€™t quite give the output I was looking for. Only the input controls are rendered (as seen in the following screenshot) instead of providing the scaffolding of label, input, and validation fields like the EditorForModel method provides.

Mvc2TemplatedHelperBeforePicNik

You end up having to provides the layout of the controls and explicitly mention the label, input controls, and validation for each property.Ā 

Modify the Template Helpers MasterPage

I soon began to miss the simple syntax of rendering all the necessary code like I was used to when using the Opinionated Input Builders outputted from the MVC Contrib.

Well, a while back Brad Wilson (one of the ASP.NET MVC 2 developers), wrote an awesome series about Templated Helpers and the last post in the series, ASP.NET MVC 2 Templates, Part 5: Master Page Templates, he addressed this granular Opinionated Input Builder type syntax!

All you do, is to override the Master Page that the templates use internally. So, inside my Master Page I layout where I want the label, validation, and input controls to go and then ASP.NET MVC 2 does the rest by resolving which Template Helper to use!

I modified the Master Page some to suite my needs (I use divs instead of tables), but overall it is the same one that he lays out on his blog.

EditorTemplates/Tempate.Master

<%@ Master Language="C#" Inherits="System.Web.Mvc.ViewMasterPage" %>






<%= ViewData.ModelMetadata.IsRequired ? "*" : "" %>
<%= ViewData.ModelMetadata.GetDisplayName() %>





<%= Html.ValidationMessage("") %>




EditorTemplate/String.aspx

<%@ Page Language="C#" MasterPageFile="Template.Master" Inherits="System.Web.Mvc.ViewPage" %>

<%= Html.TextBox("", ViewData.TemplateInfo.FormattedModelValue,
new { @class = "text-box single-line" }) %>

There are several other files that youā€™ll need. Iā€™ve grabbed most of them from Bradā€™s blog post and have them in the demo application below that you can download.

0003d725337bf3a4617919ac6126dc07PicNik

Now we can try the above scenario one more time and get the output that we were expecting.

<% Html.EnableClientValidation(); %>
<% using (Html.BeginForm()) { %>

<%= Html.EditorFor(m => m.FirstName) %>
<%= Html.EditorFor(m => m.LastName)%>
<%-- Purposely Not Show the Email ā€“%>





<% } %>

Ā 

Mvc2TemplatedHelperAfterPicNik

Ā 

cooltext439925016

Read More »