Simple jQuery Autosubmit Plugin

One issue that I have with ASP.NET is how often it injects inline styles and scripts into your pages. One example is the “AutoPostBack” attribute that you can add to your DropDownList and RadioButtonList server controls. When this attribute is added, an inline “onchange” event handler will be added to your markup along with some other scripts. Ideally, this functionality should be handled in an external JS file, and it’s really not that hard to do.

Here’s a quick jQuery plugin that will accomplish that without having to rely on .NET’s “AutoPostBack” feature.

/// <summary>
/// The parent form of the provided element(s) will be submitted when its/their value changes.
/// </summary>
/// <param name="options.ignore">An ignore option is available (array) to prevent the form from submitting when certain values are chosen. By default, options with an empty string value are ignored.</param>
/// <param name="options.trigger">If trigger is omitted, the parent form will be submitted. Otherwise, a click event will be triggered on the provided jQuery object.</param>
(function(factory) {
	if (typeof define === 'function' && define.amd) {
		// Register as an anonymous module
		define(['jquery'], factory);
	} else {
		// Browser globals
		factory(jQuery);
	}
}(function ($) {
	$.fn.autosubmit = function (options) {
		var settings = $.extend({
			'ignore': ['']
		}, options);

		this.change(function () {
			var $this = $(this);

			if ($.inArray($this.val(), settings.ignore) === -1) {
				if (typeof settings.trigger !== 'undefined') {
					settings.trigger.click();
				} else {
					$this.closest('form').submit();
				}
			}
		})

		return this;
	}
}));

Using the plugin is very easy. Create your DropDownList as usual, but give it a CssClass attribute so you can reference it easily:

<asp:DropDownList ID="myDropDownList" CssClass="auto-drop-down" runat="server">…</asp:DropDownList>

Include jQuery and the plugin file in your page, then write some JS similar to the following:

$('.auto-drop-down').autosubmit();

The plugin also allows you to specify certain values that will not autosubmit when chosen. For example, you may have a drop-down with a “Select an option” choice, in which case, you wouldn’t want to submit the form unless a different choice was made. Here’s how to ignore certain values:

$('.auto-drop-down').autosubmit({'ignore': ['', 'n/a', 'empty']});

One more thing to point out — be sure to include a submit button even if the autosubmit feature makes it unnecessary. If someone isn’t using JavaScript, they should still be able to use the drop-down on your page. Another line of JS for hiding the submit button is trivial:

$('#my-button').hide();

Minifying and Combining Multiple JavaScript Files in ASP.NET

Newer Web technologies make all kinds of new features possible, but with them come additional file bloat, slowing down your websites. Browsers can only download a limited number of files simultaneously, and all file requests that come afterward are stalled until the others are done. Fortunately, by compressing your files and combining them into a single file, you can greatly improve your site’s performance.

I recently found an ASP.NET solution that automatically minifies and combines your JavaScript files. You can read the article yourself for an in-depth look at the code, but I figured I’d post the basic steps here as a reminder to myself in future projects.

Step 1

Download the files, and extract them to the appropriate folders in your website project (create them if they don’t exist).

Step 2

Modify the file at App_Data/Site_Scripts.txt to include the scripts you want to combine, each on a separate line. If you have more than one set of scripts to combine, you can create more .txt files — just make sure they have unique file names.

Step 3

You’ll need to make some changes to your web.config file. Update the following sections, or create them if they are missing.

For IIS7:

<configuration>
   <system.webServer>
      <handlers>
         <add name="ScriptCombiner" verb="POST,GET" path="ScriptCombiner.axd" preCondition="integratedMode" type="ScriptCombiner, App_Code"/>
      </handlers>
   </system.webServer>
</configuration>

For IIS6:

<configuration>
   <system.web>
      <httpHandlers>
         <add verb="POST,GET" path="ScriptCombiner.axd" type="ScriptCombiner, App_Code"/>
      </httpHandlers>
   </system.web>
</configuration>

Step 4

Add the following to your Web form or master page, where the JavaScript files would normally appear.

<asp:Literal ID="jsLiteral" runat="server"/>

And, add the following to your code-behind in the Page_Load event.

jsLiteral.Text = ScriptCombiner.GetScriptTags("Site_Scripts", 1);

The first argument passed to the GetScriptTags method is the file name for your .txt file in the App_Data folder. The second argument is a version number. The version number appends a query string so that browsers know not to serve the file from cache (remember to update the version number when you update your JS).

And That’s It!

You should now be able to preview your page and see that all of your JS files have been combined and minified. If not, make sure you aren’t in debug mode (<compilation debug="false"/>). When in debug mode, files are not combined, but a query string is still added for the version number.

JavaScript Closure Syntax

Most documentation regarding JavaScript closures is overly complex and, in my opinion, does a poor job of explaining their use well; so here’s my attempt to dumb it down a little. Here’s the basic syntax for a JavaScript closure.

(function(varToKeepInScope) {
   return function () { alert(varToKeepInScope); };
})(varToKeepInScope);

The purpose of a closure is to allow a variable to maintain its scope when called in the future. This is a common scenario in loops, where a variable needs to be passed to an event handler, but the same variable is updated multiple times during the loop.

For example, imagine that you want to add a mouseover handler to every <a> element on your page so that when the user hovers over a link, the title attribute is displayed as a custom-styled tooltip.

var tooltip;
var anchors = document.getElementsByTagName('a');
for (var n = 0, anchor; anchor = anchors[n++];) {
   tooltip = anchor.getAttribute('title');
   anchor.addEventListener('mouseover', function() {
      showTooltip(tooltip);
   });
}

Unfortunately, the above code will not work, and the same tooltip will display over every link. That’s because the tooltip variable continues to be updated until the end of the loop, and you end up passing its last updated value to the showTooltip() function when the mouseover event is triggered.

Closures work by using an anonymous function to return a new function with a new scope for the variable. Here’s how the code above can make use of a closure to retain the appropriate value of the tooltip.

var tooltip;
var anchors = document.getElementsByTagName('a');
for (var n = 0, anchor; anchor = anchors[n++];) {
   tooltip = anchor.getAttribute('title');
   anchor.addEventListener('mouseover', (function(scopedTooltip) {
      return function () { showTooltip(scopedTooltip); };
   })(tooltip));
}

Very simple and a common use-case for closures.