Loading images last with jQuery

Add to FacebookAdd to DiggAdd to Del.icio.usAdd to StumbleuponAdd to RedditAdd to BlinklistAdd to TwitterAdd to TechnoratiAdd to Yahoo BuzzAdd to Newsvine

There are lots of ways to make your webpages faster and more responsive. YSlow is a great tool to help you find many great ways to make a particular page faster.

One of the best things you can do is reduce the number of requests (css/js/images/etc) to the server. Typically, this would mean that you would combine files – merge all of your JS and CSS (and minify while you are at it), and use CSS Sprites to combine images.

One major problem of using CSS Sprites is that it can be quite painful to maintain. Over time, if you want to add or change some of your images – you basically need to rebuild and replace the combined images and all of the CSS rules specifying coordinates. Sometimes, this makes the CSS Sprite technique unreasonable to implement.

In one such case, we had about 50 images in one application that were causing the page to take a long time to load. These images were previews of some different design choices that the user could make. The design choices themselves (and their previews) were database driven so that we can add new designs through an admin interface. So, CSS Spriteing the previews would seriously hamper that flexibility.

One other design consideration was that the previews weren’t that important – the page was fully functional and usable without the images. In fact, the designs weren’t even visible until you toggled the design menu.

There is a lazy loader plugin for jQuery already available here – but it didn’t fit our needs. Instead of skipping images in order to get the page working as soon as possible (and initiate the load once the page is usable) – it is made to skip loading offscreen images until they are scrolled into view. It might have somewhat worked for our needs – but I thought it was better to load the images as soon as possible, instead of waiting for the design menu to be expanded to initiate the load. That way, most of the time the designs would be visible by the time they open the menu – but it wouldn’t interfere with the rest of the interface.

My solution was to set the src for all of the previews to a single animated loading image – like one you can get here. Then, I set a custom attribute on the image for the real preview’s url. Finally, some jQuery code runs after the page is done loading which replaces each src attribute with the url in the custom attribute, which will load the real image.

Sample HTML:

<ul>
    <li templateid="7bcf8f23-fdd0-45c5-a429-d2ffb59e47f0" class="selected"><span>3D Dots
        Dark</span>
        <img src="/static/img/ajax-loader-small.gif" deferredsrc="/resources/7bcf8f23-fdd0-45c5-a429-d2ffb59e47f0/preview.jpg"
            class="deferredLoad" alt="3D Dots Dark" />
    </li>
    <li templateid="b1a09e28-629e-472a-966e-fc98fc269607"><span>3D Dots Lite</span>
        <img src="/static/img/ajax-loader-small.gif" deferredsrc="/resources/b1a09e28-629e-472a-966e-fc98fc269607/preview.jpg"
            class="deferredLoad" alt="3D Dots Lite" />
    </li>
    <li templateid="e121d26a-9c8f-466f-acc7-9a79d5e8cfa9"><span>Beauty</span>
        <img src="/static/img/ajax-loader-small.gif" deferredsrc="/resources/e121d26a-9c8f-466f-acc7-9a79d5e8cfa9/preview.jpg"
            class="deferredLoad" alt="Beauty" />
    </li>
    <li templateid="322e4c7a-33e7-4e05-bb72-c4076a83a3d0"><span>Black and White</span>
        <img src="/static/img/ajax-loader-small.gif" deferredsrc="/resources/322e4c7a-33e7-4e05-bb72-c4076a83a3d0/preview.jpg"
            class="deferredLoad" alt="Black and White" />
    </li>
    <li templateid="57716da9-91ef-4cf0-82f1-722d0770ad7f"><span>Blank</span>
        <img src="/static/img/ajax-loader-small.gif" deferredsrc="/resources/57716da9-91ef-4cf0-82f1-722d0770ad7f/preview.jpg"
            class="deferredLoad" alt="Blank" />
    </li>
    <li templateid="a79e1136-db47-4acd-be3e-2daf4522796d"><span>Blue Leaves</span>
        <img src="/static/img/ajax-loader-small.gif" deferredsrc="/resources/a79e1136-db47-4acd-be3e-2daf4522796d/preview.jpg"
            class="deferredLoad" alt="Blue Leaves" />
    </li>
    <li templateid="03cb737d-4da7-46d5-b4e4-5ad4b4a3aaf4"><span>Blue Open</span>
        <img src="/static/img/ajax-loader-small.gif" deferredsrc="/resources/03cb737d-4da7-46d5-b4e4-5ad4b4a3aaf4/preview.jpg"
            class="deferredLoad" alt="Blue Open" />
    </li>
    <li templateid="899dff2f-38ba-44f7-9fe2-af66e62674a4"><span>Compass</span>
        <img src="/static/img/ajax-loader-small.gif" deferredsrc="/resources/899dff2f-38ba-44f7-9fe2-af66e62674a4/preview.jpg"
            class="deferredLoad" alt="Compass" />
    </li>
</ul>

Sample javascript:

$(function(){
        $("img.deferredLoad").each(function() {
            var $this = $(this);
            $this.attr("src", $this.attr("deferredSrc")).removeClass("deferredLoad");
        });
});

Really Nice Looking Export to Excel using Table Formatting

Inevitably, someone is going to want your data exportable to an Excel format, no matter how many different ways you let them look at right on your site–and they’re going to want it to look really nice.

If you’re just going to a CSV format, it’s pretty easy to do, but if it opens in Excel, none of the cells are formatted initially.  It can look good eventually, but you have to manually format it after the export.  It would sure be nice if you could format it better from the code itself.  For me, I thought it would be too tedious and time-consuming to actually create the Excel Spreadsheet.  I wanted something quicker.

Using a DataGrid for the bulk of the actual data works well as it renders as a table, and Excel seems to work well with table formats.  I used an HtmlTextWriter for this purpose.

HtmlTextWriter hw
dg.RenderControl(hw)

However, the DataGrid wasn’t the only thing I wanted to export.  What I wanted was a nice big heading that was bolded, nice subheadings, nice spacing, and a bunch of things like that.  What I found is that if I just wrote table structure syntax, I could do basically everything I wanted.

What I did here was to write a large, centered heading that spanned 8 columns (the entire width of my report).  Both the “th” and the “h1″ tags impact the way it renders in Excel.  I added the colspan and alignment attributes on the th tag, and it worked great.  Then I added a blank link by simply writing a br tag.  Here’s the code:

hw.WriteLine("<table><tr><th colspan=\"8\" align=\"center\"><h1>My Nice Looking Report</h1></th></tr></table>");
hw.WriteLine("<br>");

The rendering just follows down the page pretty nicely.  I added subheaders with h2 tags, and I played around with color and other attributes as well.  Then, after you export to Excel, the moment you open it up, all the formatting is there.  It looks pretty nice–particularly so in product demos.  Even if clients opt for csv format so they can put it into reporting software, the look that this provides gives great curb appeal.

Here’s the code for the sub heading and the legend for the report.  The term takes up two cells, and the description is confined to the other 6 cells (just because the total width was 8 cells/td’s).

hw.WriteLine("<table>");
hw.WriteLine("<tr><td colspan=\"8\"><h3>Report Legend</h3></td></tr>");

hw.WriteLine("<tr><td colspan='2'>Incomplete Evaluations</td><td colspan='6'>Evaluations assigned but not been completed.</td></tr>");
hw.WriteLine("<tr><td colspan='2'>Completed Evaluations</td><td colspan='6'>Evaluations assigned that have been completed.</td></tr>");
hw.WriteLine("<tr><td colspan='2'>Request Reviews</td><td colspan='6'>Total number of requests for reviews.</td></tr>");
hw.WriteLine("<tr><td colspan='2'>Unfulfilled Request Reviews</td><td colspan='6'>Total number of requests not yet reviewed.</td></tr>");
hw.WriteLine("<tr><td colspan='2'>Request Responses</strong>/td><td colspan='6'>Total number of request review responses. </td></tr>");

hw.WriteLine("</table>");
hw.WriteLine("<br>");

Again, this works really well for me. It allows me to easily control the format without actually creating an Excel Spreadsheet in the code itself.

Unexpected benefits of Precompilation of LINQ

Add to FacebookAdd to DiggAdd to Del.icio.usAdd to StumbleuponAdd to RedditAdd to BlinklistAdd to TwitterAdd to TechnoratiAdd to Yahoo BuzzAdd to Newsvine

I once had a manager who told me – I can solve any maintenance problem by adding a layer of abstraction.  I can solve any performance problem by removing a layer of abstraction.

I think LINQ to SQL is a wonderful way to abstract the persistence layer elegant, easy to use, easy to manipulate, and easy to maintain lines of code.  Instead of writing SQL which amounts to “how to retrieve” the data – you manipulate an expression tree that gets closer to specifying “what data I want”.  The upside of this is huge – you can change the expression tree at any level of your code, and let .NET decide how to best write the SQL at the last possible moment – which effectively gits rid of dealing with intermediate results and inefficiently written SQL.  Unfortunately, this abstraction does indeed cause a performance hit – the translation/compilation of the tree to SQL – and it’s probably much bigger than you would think.  See http://peterkellner.net/2009/05/06/linq-to-sql-slow-performance-compilequery-critical/ to see what I mean.  In my analysis (using ANTS Profiler), when using uncompiled LINQ – the performance hit is usually about 80% compilation and only 20% retrieving the data!  Thankfully, .NET does allow you to precompile a LINQ query and save the compilation to use over and over again.

Your natural tendency when hearing those kind of numbers might be to precompile every single LINQ query you write.  There’s a big downside to doing that, though – you lose the ability to manipulate the compiled query in other parts of your code.  Another downside is that the precompilation code itself is fairly ugly and hard to read/maintain.

I’m a big believer in avoiding “premature optimization”.  What happens if you precompile everything, and in a version or two Microsoft resolves the issue and caches compilations for you behind the scenes?  You have written a ton of ugly code that breaks a major benefit of LINQ to SQL and is totally unnecessary.

Instead, I recommend you go after the low hanging fruit first – precompile the most frequently accessed queries in your application and the ones that gain no benefit from manipulating the expression tree.  In the applications I work on – there is a perfect case that fits both of these – the “get” method that returns the LINQ object representation of a single row in the database.  These are hit quite often – and there is absolutely no case where the expression tree is further refined.

The old way it was written:

	public static Item Get(int itemid) {
		return (from i in DataContext.Items
			where i.ItemID == itemid
		select i).First();
	}

The new way with Precompiled LINQ:

	private static Func<ModelDataContext, int, Item>
		GetQuery = CompiledQuery.Compile(
			(ModelDataContext DataContext, int itemid) =>

				(from i in DataContext.Items
					where i.ItemID == itemid
				select i).First()

				);

	public static Item Get(int itemid) {
		return GetQuery.Invoke(DataContext,itemid);
	}

Applying this fairly simple change to the application, I’d estimate we got 80%+ of the benefits of compiled LINQ, at the expense of a few extra lines of code per object/table and absolutely no loss of the tree manipulation.

Extended DropDownList Control

Add to FacebookAdd to DiggAdd to Del.icio.usAdd to StumbleuponAdd to RedditAdd to BlinklistAdd to TwitterAdd to TechnoratiAdd to Yahoo BuzzAdd to Newsvine

It’s a very common situation.  A dropdownlist has a parent whose selected value determines what options will be bound to it.  But what happens when there are none?  And what happens if there’s only one option?  And why do I have to enter code to insert “Select an Item” to the list?  And why does it continue to display even when no item has been selected on its parent and it doesn’t have any values at all?  And why does it continue to display immediately after the parent’s value has been changed and the page is reloading?

Well, what if it wasn’t that way?  What if it accounted for all those things?  That would be really nice, and, in fact, it actually is quite nice.

This extended dropdownlist control has the following additional parameters:

  • ParentDropDownListID - Specifies the id field of the parent dropdownlist.
  • ParentItemUnpopulatedText – Specifies the text to display when the parent dropdownlist has yet to be populated.  The dropdownlist itself will be hidden and this text appears in its place, giving the user appropriate feedback.  The default is “n/a” since this dropdownlist really isn’t applicable until its parent is populated.  (This comes up in a series of three or parent/child dropdownlists.)
  • ParentItemNotSelectedText -Specifies the text to display when the parent dropdownlist has been populated but no item has yet been selected (The selected item is “Select an item”.)  So, for a state/city relationship it could say “Please select a state” or “n/a”–whatever you want.  But the dropdownlist itself is hidden, so the user can’t select it and wonder why there’s nothing in it to select.
  • ControlsToHideOnChange – This actually specifies children dropdownlists to hide whenever the selected item changes.  In a state/city relationship, if you change the state, the city dropdownlist will need to be repopulated.  However, sometimes the page takes a little while to load and the user may try to select a city before that gets repopulated.  To avoid the confusion, the city dropdownlist, whose ID is specified in this parameter, will be immediately hidden via JavaScript and a message will appear in its place indicating that the user needs to wait until it is repopulated.  You can actually specify multiple children to hide, so if you had county and city children, both would be hidden while the page reloads.  The text is specified in the ChildrenRepopulatingText.
  • ChildrenRepopulatingText – The text that replaces the child controls specified in ControlsToHideOnChange whenever the selected item for this control (the parent) changes.
  • HasSelectedItemText – true/false – defines whether or not a “Select Item” option should be added to the dropdownlist.  I will probably eliminate this and just add one based on whether or not the SelectItemText parameter is specified.
  • SelectItemText - Specifies the text to add as the first item (with a value of -1) to the dropdownlist.
  • NoItemsText – Specifies the message to display if there are no items in the dropdownlist, since an empty dropdownlist is annoying.  The actual dropdownlist will be hidden and this text will display.  So, this could be “There were no cities defined for the state you selected.”

Additionally, if there is only one item bound to the dropdownlist, the dropdownlist goes ahead and selects that item.  The dropdownlist itself is hidden, and the item text is displayed as a message.  It is just annoying when you have a dropdownlist with a single item, but you still have to select it because you have a “Select Item” option that is the initially selected item.

So, that’s the extended control as it is now.  Hopefully, it will save coding time and provide a better overall user experience.
NOTE: The control as it is written does use Jquery commands as well, so if you’re not referencing that, you’ll need to rewrite the JavaScript.


public class ExtendedDropDownList : DropDownList
{
    public bool HasSelectItemText
    {
        get
        {
            object o = ViewState["HasSelectItemText"];
            if (o == null)
                return false;
            else
                return (bool)o;
        }
        set
        {
            ViewState["HasSelectItemText"] = value;
        }
    }

    public string SelectItemText
    {
        get
        {
            object o = ViewState["SelectItemText"];
            if ((o == null) || ((string)o == ""))
                return "Select an Item";
            else
                return (string)o;
        }
        set
        {
            ViewState["SelectItemText"] = value;
        }
    }

    public string NoItemsText
    {
        get
        {
            object o = ViewState["NoItemsText"];
            if ((o == null) || ((string)o == ""))
                return "No items available to select";
            else
                return (string)o;
        }
        set
        {
             ViewState["NoItemsText"] = value;
        }
    }

    public string ParentDropDownListID
    {
        get
        {
            if (ViewState["ParentDropDownListID"] == null)
                ViewState["ParentDropDownListID"] = "";
            return (string)ViewState["ParentDropDownListID"];
        }
        set
        {
            ViewState["ParentDropDownListID"] = value;
        }
    }

    public string ParentItemNotSelectedText
    {
        get
        {
            if (ViewState["ParentItemNotSelectedText"] == null)
                ViewState["ParentItemNotSelectedText"] = "";
            return (string)ViewState["ParentItemNotSelectedText"];
        }
        set
        {
            ViewState["ParentItemNotSelectedText"] = value;
        }
    }

    public string ParentItemUnpopulatedText
    {
        get
        {
            if (ViewState["ParentItemUnpopulatedText"] == null)
                ViewState["ParentItemUnpopulatedText"] = "n/a";
            return (string)ViewState["ParentItemUnpopulatedText"];
        }
        set
        {
            ViewState["ParentItemUnpopulatedText"] = value;
        }
    }

    public string ControlsToHideOnChange
    {
        get
        {
            if (ViewState["ControlsToHideOnChange"] == null)
                ViewState["ControlsToHideOnChange"] = "";
            return (string)ViewState["ControlsToHideOnChange"];
        }
        set
        {
            ViewState["ControlsToHideOnChange"] = value;
        }
    }

    public string ChildrenRepopulatingText
    {
        get
        {
            if (ViewState["ChildrenRepopulatingText"] == null)
                ViewState["ChildrenRepopulatingText"] = "Repopulating Options...";
            return (string)ViewState["ChildrenRepopulatingText"];
        }
        set
        {
            ViewState["ChildrenRepopulatingText"] = value;
        }
    }

    public string[] ControlsToHide
    {
        get
        {
            return ControlsToHideOnChange.Split(',');
        }
    }

    public override void DataBind()
    {
        base.DataBind();

        int itemCount = this.Items.Count;
        if (HasSelectItemText && itemCount > 1)
            this.Items.Insert(0, new ListItem(SelectItemText, "-1"));
        if (itemCount == 0)
            this.SelectedIndex = -1;
        else
            this.SelectedIndex = 0;
    }

    protected override void CreateChildControls()
    {
        base.CreateChildControls();
        if (ControlsToHideOnChange != "")
        {
            ServerPage page = GetPage();
            foreach (string s in ControlsToHide)
            {
                this.Attributes["onchange"] = "$('#" + page.FindControl(s).ClientID + "').hide();" + "$('#" + page.FindControl(s).ClientID + "').parent().text('" + ChildrenRepopulatingText + "');" + this.Attributes["onchange"];
            }
        }
    }

    protected override void Render(System.Web.UI.HtmlTextWriter writer)
    {
        EnsureChildControls();

        DropDownList parent = (DropDownList)GetPage().FindControl(ParentDropDownListID);
        bool hasUnselectedParent = (ParentDropDownListID != "") && (parent != null) && (parent.Items.Count > 0) && (parent.SelectedValue == "-1");
        bool hasUnpopulatedParent = (ParentDropDownListID != "") && (parent != null) && (parent.Items.Count == 0);

        writer.WriteLine("<div>");

        if (hasUnselectedParent)
        {
            this.Items.Clear();
            writer.WriteLine("<span>" + ParentItemNotSelectedText + "</span>");
            this.Attributes.CssStyle["display"] = "none";
        }
        else if (hasUnpopulatedParent)
        {
            this.Items.Clear();
            writer.WriteLine("<span>" + ParentItemUnpopulatedText + "</span>");
            this.Attributes.CssStyle["display"] = "none";
        }
        else
        {
            if (this.Items.Count == 0)
            {
                writer.WriteLine("<span>" + NoItemsText + "</span>");
                this.CssClass = "hide";
            }
            else if (this.Items.Count == 1)
            {
                writer.WriteLine("<span>" + this.Items[0].Text + "</span>");
                this.CssClass = "hide";
            }
        }

        base.Render(writer);

        writer.WriteLine("</div>");
    }

    private Foliotek.Components.ServerPage GetPage()
    {
        System.Web.UI.Control control = this;
        while (control.GetType() != Type.GetType("Foliotek.Components.ServerPage"))
        {
            control = control.Parent;
        }
        return (Foliotek.Components.ServerPage)control;
    }
}

Getting the width of a hidden element with jQuery using width()

Add to FacebookAdd to DiggAdd to Del.icio.usAdd to StumbleuponAdd to RedditAdd to BlinklistAdd to TwitterAdd to TechnoratiAdd to Yahoo BuzzAdd to Newsvine

I recently ran into a problem with jQuery’s width().  The problem is with a visible element that is inside a hidden element will return a value of 0 instead of its’ actual calculated width.  After messing around with it for a little bit I finally came up with a solution.  The method I used involved adding some CSS properties to the hidden element.  The CSS properties involved are position, visibility, and display.

//$HiddenItem is the element that is wrapping the element that you want the width of
//$Item is the element you want the width of

$HiddenItem.css({
    position: "absolute",
    visibility: "hidden",
    display: "block"
})
$Item.width();

$HiddenItem.css({
    position: "",
    visibility: "",
    display: ""
})

After setting the above CSS properties on the element, you can then call width() and the correct value will be returned. After you call the width() method you should clear the properties in order to return the element to the way it was.

Setting the properties to an empty string is probably not the best way to do it though. What if there was a position value already set? Using this method would clear out that initial values of the CSS properties.

I found the swap() method to be handy in this situation. I found this method while looking through the jQuery source code.

// A method for quickly swapping in/out CSS properties to get correct calculations
swap: function( elem, options, callback ) {
     var old = {};

     // Remember the old values, and insert the new ones
     for ( var name in options ) {
          old[ name ] = elem.style[ name ];
          elem.style[ name ] = options[ name ];
     }

     callback.call( elem );

     // Revert the old values
     for ( var name in options )
          elem.style[ name ] = old[ name ];
     }
}

By using the swap method, the old CSS properties will be remembered and reapplied after finding the width of the element.

The swap method takes in 3 parameters:

  1. The element that you would like to swap the CSS properties on
  2. CSS key/value pairs that you want to change
  3. A callback function to call after the properties are set

To rewrite the above to use the swap method I would do the following:

var props = { position: "absolute", visibility: "hidden", display: "block" };
var itemWidth = 0;

$.swap($HiddenItem[0], props, function(){
     itemWidth = $Item.width();
});

//Use itemWidth

I coded up a small example on jsbin. Here is the link http://jsbin.com/ofine3/2.

$HiddenItem.width();

The non-breaking space “ ”

Add to FacebookAdd to DiggAdd to Del.icio.usAdd to StumbleuponAdd to RedditAdd to BlinklistAdd to TwitterAdd to TechnoratiAdd to Yahoo BuzzAdd to Newsvine

This post may sound elementary to those of you who went through college after the web development was in full swing.  Admittedly, that was just slightly before my time.  So, what was a small epiphany for me may be common knowledge to you, but please pardon my ignorance and delight at what I learned.

Sometimes you just need a little more space somewhere, and fortunately, sometime long ago when I was just starting to work on the web, someone introduced me to the beloved “&nbsp;”.  Since that time, I have used it occasionally whenever it was too tedious to add space another way.

However, I recently needed to have a cell in a header row define the space for the column.  I don’t recall the exact circumstance now, but for whatever reason, defining no wrap wasn’t available.

Enter the often-used but seldom understood &nbsp;.  I needed the text in this column to not break at the spaces.  I was working with another person, when it occurred to me that the non-breaking space is probably a non-breaking space.

I replaced the spaces with &nbsp; and the problem was solved!

Linq Expressions on an Interface

Add to FacebookAdd to DiggAdd to Del.icio.usAdd to StumbleuponAdd to RedditAdd to BlinklistAdd to TwitterAdd to TechnoratiAdd to Yahoo BuzzAdd to Newsvine

One thing I found myself doing quite a bit an often causing logic errors was comparing
dates in Linq queries. For example, if I want to get games that occur between a date range, I might be
doing something like this :

	public static IQueryable<Competition> GetBetweenDates(DateTime startDate, DateTime endDate)
	{
		return (from comp in DataContext.Competitions
				where comp.Date >= startDate && comp.Date <= endDate
				select comp);
	}

I then want to get a list of tournaments that occur between a date range, and I might
essentially rewrite this code using a couple different variables. Rather, I can implement
a common interface on these classes and have an expression applied to all classes that
implement this interface.

	public interface IDate
	{
		DateTime Date { get; set; }
	}

	public partial class Competition : DataBase, IDate
	{
		...
	}

	public static class Expressions
	{
        public static Expression<Func<T, bool>> GetBetweenDates<T>(DateTime start, DateTime end)
            where T : IDate
        {
            return (t => t.Date >= start && t.Date <= end);
        }
	}

Then, rather than rewriting this for each class with a date, I can just apply this expression
to my queries.

	public static IQueryable<Competition> GetBetweenDates(DateTime startDate, DateTime endDate)
	{
		return (from comp in DataContext.Competitions
			select comp).Where(
                             Expressions.GetBetweenDates<Competition>(startDate, endDate));
	}

jQuery Custom Selector for selecting elements by exact text :textEquals

Add to FacebookAdd to DiggAdd to Del.icio.usAdd to StumbleuponAdd to RedditAdd to BlinklistAdd to TwitterAdd to TechnoratiAdd to Yahoo BuzzAdd to Newsvine

I needed a way to find labels based on the text that they contained.  I thought about using :contains() for this, but in this particular case the text items I was searching on were names and I could have similar names that :contains() could incorrectly match on.  For instance, if I was searching for “Banks, Tim” and there was an item with the text “Banks, Timothy” I would get both items returned.  This is not the behavior I was looking for.

I decided to write a little custom selector to match on exact text.  Here is the code for the custom selector:

$.expr[':'].textEquals = function(a, i, m) {
return $(a).text().match("^" + m[3] + "$");
};

What is happening here is I am using a regular expression to test if the start and end of the element’s text matches the string passed in.  Now I could search for the name “Banks, Tim” on a label element like this:

$("label:textEquals('Banks, Tim')");

Make Table Rows Sortable Using jQuery UI Sortable

Add to FacebookAdd to DiggAdd to Del.icio.usAdd to StumbleuponAdd to RedditAdd to BlinklistAdd to TwitterAdd to TechnoratiAdd to Yahoo BuzzAdd to Newsvine

So you want to make table rows sortable using jQuery UI? Luckily, the Sortable interaction does most of the work for you.

But there’s a catch: one problem that I ran into when implementing this (with UI version 1.7) was the cell widths of the row would collapse once I started dragging it.

Suppose you have a table of data, like this one:

<table id="sort" class="grid" title="Kurt Vonnegut novels">
	<thead>
		<tr><th>Year</th><th>Title</th><th>Grade</th></tr>
	</thead>
	<tbody>
		<tr><td>1969</td><td>Slaughterhouse-Five</td><td>A+</td></tr>
		<tr><td>1952</td><td>Player Piano</td><td>B</td></tr>
		<tr><td>1963</td><td>Cat's Cradle</td><td>A+</td></tr>
		<tr><td>1973</td><td>Breakfast of Champions</td><td>C</td></tr>
		<tr><td>1965</td><td>God Bless You, Mr. Rosewater</td><td>A</td></tr>
	</tbody>
</table>

Your first attempt to make it sortable might look like this:

$("#sort tbody").sortable().disableSelection();

And it actually works, but there is a bit of a problem. The cell widths seem to be collapsing once you start dragging a row (notice how close the “C” cell is to the “Breakfast of Champions” cell). It looks like this:

Sortable row collapsed widths

The problem has to do with the helper object. The helper object is basically the DOM element that follows the cursor during the drag event. When it is created by default, the cells collapse to the size of the content inside of them.

You can specify a function that returns a jQuery object to create a custom helper object. By creating a function that will keep the cell widths consistent, this problem can be fixed.

// Return a helper with preserved width of cells
var fixHelper = function(e, ui) {
	ui.children().each(function() {
		$(this).width($(this).width());
	});
	return ui;
};

$("#sort tbody").sortable({
	helper: fixHelper
}).disableSelection();

Now it works as expected:
Sortable row fixed

Keep Original Variable State Between Event Binding and Execution – JavaScript

Add to FacebookAdd to DiggAdd to Del.icio.usAdd to StumbleuponAdd to RedditAdd to BlinklistAdd to TwitterAdd to TechnoratiAdd to Yahoo BuzzAdd to Newsvine

Also known as: Binding Events Inside of a Loop with jQuery

Sometimes I want to create a closure that accesses a variable in the state that it was in when the closure was created. I don’t want to know what the current value is, I want to know what the value was when I created the function. I may want to do this when binding an event to a DOM object, or when executing a function inside of setTimeout().

The Problem

Here is an example of the problem using the jQuery library (consider what will happen when you click on any of the li elements):

	$(function() {
		$("body").append("<ul id='container'></ul>");

		for (var i = 0; i < 5; i++)
		{
			var $item = $("<li />").text("Item " + i);
			$("#container").append($item);

			$item.click(function() {
				alert("You clicked number " + i);  // always "You clicked number 5"
			});
		}
	});

The event handler will always use the final value of the variable “i”, which will be 5 in this case. One way to fix this problem is to create a function and pass “i” as a formal parameter:

Solution 1 – Traditional Function

	function bindItem($item, ind) {
		$item.click(function() {
			alert("You clicked number " + ind);  // Works as expected
		});
	}

	$(function() {
		$("body").append("<ul id='container'></ul>");

		for (var i = 0; i < 5; i++)
		{
			var $item = $("<li />").text("Item " + i);
			$("#container").append($item);
			bindItem($item, i);
		}
	});

Since this passes the variable as a parameter to a function, the variable “ind” will always remain the same, even if “i” changes after the function finishes execution. The function bindItem() creates a new scope. Any variables (passed as parameters or declared inside the function) will reserve their own space in memory, and will not be affected by the state of the variable ‘i’. Thanks to reddit user Mych for correcting me.

This is what I wanted in the first place, but we may not want to have a named function here – if we used a closure we would still have access to variables in the same scope (like $item) without having to pass them as parameters to bindItem().

This does the trick:

Solution 2 – Self Executing Function

	$(function() {
		$("body").append("<ul id='container'></ul>");

		for (var i = 0; i < 5; i++)
		{
			var $item = $("<li />").text("Item " + i);
			$("#container").append($item);

			(function() { // Closure here here instead of "bindItem()"
				var ind = i;
				$item.click(function() {
					alert("You clicked number " + ind); // Works as expected
				});
			})(); // Execute immediately
		}
	});

This is a trick I first saw in the jQuery plugin development tutorial, in the custom alias section.

Declaring the closure creates a new scope in the loop. Any variables (such as ‘ind’) passed as parameters or declared inside of this scope will reserve a new space in memory that is not a reference to ‘i’.

The extra parentheses at the end of a block like this “(function() {…})()” cause the closure to execute immediately .

These are just a couple ways to solve the problem of variable state changing between event binding and execution. Closures are a powerful language feature that makes JavaScript very flexible, but when execution of them is being delayed via a timeout or event handler, it is important to keep track of the variables that they are closed over.