Showing posts with label javascript. Show all posts
Showing posts with label javascript. Show all posts

2/10/2013

ASP.NET MVC 4 Highlights: Bundling and Minification

By: John V. Petersen


In the first installment of this series, I explored a few of the new features in ASP.NET MVC 4, including the new default project templates, mobile templates, and display modes. Since that article, ASP.NET MVC 4 has been released to beta. For brevity’s sake, when I refer to MVC the design pattern, I’m referring to the ASP.NET implementation of the pattern. In this installment, I’m going to focus on one of MVC’s most useful features: integrated JavaScript and CSS bundling and minification.
One of the most important considerations in any Web application is the size of the content rendered to the browser. Bundling and minification handle two important tasks. First, all of the disparate JavaScript and CSS files are combined into one or more files. Second, the JavaScript and CSS code is minified by means of removing all of the carriage returns and line feeds as well as verbose variable names in favor of shorter (less verbose) alternatives.
With bundling, there are fewer resources that need to be rendered to the browser. With minification, the size of such resources is much smaller, often by as much as 70% or more!
These are not new concepts. Tools like JSMin and YUI have been around for several years. You have always been able to incorporate these bundling and minification solutions. What’s new are the integrated features baked into the MVC framework that handle these bundling and minification tasks out of the box.
Bundling and Minification “Out of the Box”
Figure 1 illustrates what you get out of the box for bundling and minification. Like all ASP.NET applications, everything starts in the Global.asax Application_Start() event handling code.
Click for a larger version of this image.

Figure 1: These code windows represent the out-of-the-box bundling and minification implementation in Global.asax and _Layout.cshtml.

In that code, there’s a call to:
BundleTable.Bundles.RegisterTemplateBundles();
The code for this method is burned into the System.Web.Optimization.dll. Figure 2 illustrates what that code looks like.
Click for a larger version of this image.

Figure 2: This code represents the out-of-the-box implementation code for RegisterTemplateBundles in System.Web.Optimization.

The code is straightforward in that bundles are created and files are added to the bundles. There are two ways to add files. One way is to refer to the file specifically. The second way is to specify a directory along with a file pattern search string. In the second method, the code can selectively traverse subdirectories to add content.
Each method has their respective pros and cons. When you specify the files, you know exactly what is getting into your bundled and minified files. This method requires more code. When you add directories, you don’t have to write as much code, but the possibility exists for unwanted code in the bundled and minified file. Choosing between adding files, directories or some combinatin thereof is a matter personal preference.
To use this functionality, there are a few concepts you must be familiar with:
  • Bundle Class: Encapsulates one or more files to be bundled and minified
  • AddFile() Method: Adds a specifically named file to the bundle
  • AddDirectory() Method: Adds files that match a file search string within the specified directory
  • Transform Property: An instance of IBundlerTransform, the object in this property performs the minification task
  • Path Property: The string that identifies the bundle within the Bundles Member in BundleTables
As you will see in a moment, as is custom in MVC, if you don’t like the default out of the box functionality in MVC, you can substitute your own functionality. First, take a look at what the default functionality gives you. Figure 3 illustrates how the disparate javaScript (JS) and Cascading Style Sheet (CSS) files are rendered to the browser.
Click for a larger version of this image.

Figure 3: The network view lists the bundled and minified CSS and JS files (with a query string parameter that is explained in the next section).

Note the file paths:
/Content/css/Content/themes/base/css/Scripts/js
These are the paths specified when the bundles were created. Figure 4 illustrates how the minified JavaScript appears.
Click for a larger version of this image.

Figure 4: This is the minified and bundled JavaScript content as rendered to the browser.

Why Is a Query String Parameter Added to the JavaScript and CSS Files?
Every time the page is refreshed, the server-side code is executed, causing the _Layout.cshtml Razor Template to evaluate. You always want the client to recognize the latest JavaScript and CSS content. If the file were always named the same, the browser may reference its cache. This behavior can always be configured at the browser level. However, that is not usually a feasible solution because it requires each computer to be specifically configured. If you have the chance to control behaviors that are essential to your applications at the server level, take it! With the addition of the query string, the client will interpret this to be a new file and therefore, rely on its cache.
You might be thinking that the call to ResolveBundleUrl is required for the bundling and minification to work. It’s not. To illustrate, I’ll replace the code for /Content/css with the following:
<link href="~/Content/css" rel="stylesheet" type="text/css" />
Figure 5 illustrates that bundling and minification still takes place. The only difference is the file name. Without the call to ResolveBundleUrl, the query string parameter is not added.
Click for a larger version of this image.

Figure 5: If the ResolveBundleUrl call is omitted, a query string parameter will not be added.

Essentially, that’s it! That’s what we get for free. But what about debugging? I don’t want my code minified in those cases. Am I stuck?
Of course not! In MVC, with almost no exception, you can override the default out-of-the-box behavior for your own behavior. In the next section, you will see how to create your own custom bundler and minification class.

Creating a Custom Bundler
If there are limitations to how the bundling and minification feature is implemented in the beta, these two would be at the top of the list:
  • The code to create the bundles is burned in a dll.
  • There is no way to make the default functionality sensitive to debug vs. release modes.
While bundling is something you probably always want, minification isn’t. While debugging, you need the unminified code to be rendered. Out of the box, using the default bundler, you cannot conditionally bundle. Let’s solve that problem now. The custom bundler code in Listing 1 solves the problem.
What’s the Second Bool Variable in AddFile()?
The second Bool Variable is the throwIfNotExist parameter. If the specified file does not exist, you can elect to have an exception thrown. In the default beta implementation, this parameter is set to false.
If you don’t want to be explicit with your files, the code could be simplified to what is illustrated in Listing 2.
The AddDirectory() method has four parameters:
  • directoryVirtualPath: the root directory used to search for files to bundle and minify
  • searchPattern: specifies the pattern to limit which files are included in the bundle
  • searchSubDirectories: if true, the process recursively searches all contained subdirectories under the directoryVirtualPath
  • throwIfNotExist: if true, the process throws an exception if the specified directoryVirtualPath does not exist
In this simplified code, every js file under /Scripts and every CSS file under /Content is included.
In both cases, a compiler directive is added to specify the transformer used to drive the minification process. Out of the box, there is a class called NoTransform. As the name implies, this class does not minify. You need such a class because the bundler instance requires a transformer:
var bundle = new Bundle("~/Scripts/js", jstransformer);
The bundler does not care what the transformer does. As long as it gets an instance that conforms to IBundleTransformer, the Bundle instance will be happy. Listing 3 shows what the NoTransform class is.
I Like the YUI Minifier; Can I Use That?
The nice thing about the way bundling and minification was implemented in ASP.NET MVC is that you don’t have to give up using utilities that you are currently using. The implementation works very much like the way IDependencyResolver works. In Version 3, an inversion of control container adapter was added to abstract away the details of any specific IoC container from the framework. The bundling and minification process illustrated here works very much the same way. The process begins with creating a custom instance of IbundlerTransform, as shown in Listing 4.
To take advantage of the YUICompressor Transform Class, the code in Listing 2 that loads the proper transformer must be changed to the following:
bool isDebug;
#if DEBUG isDebug = true; #endif
if (isDebug) { jstransformer = new NoTransform("text/javascript"); csstransformer = new NoTransform("text/css"); } else { jstransformer = new YUITransform(contentType.javascript); csstransformer = new YUITransform(contentType.css); }
I changed the debug-checking process slightly, because I am gradually moving to a solution that is testable. The next step involves creating a custom abstraction over the base Bundle Class that begins to abstract away the details of which files to add. I’ll leave that exercise to you to explore.
File Ordering within a Bundle
By default, JavaScript files are first ordered alphabetically within a bundle. Then, the files are restacked around known libraries. For example, jQuery - related files occur first in the bundle. Within the jQuery group, the files are sorted alphabetically. For CSS files, the files are first sorted alphabetically. Then, if the files reset.css or normalize.css exist, that content appears at the top of the bundled CSS file. Figure 6 illustrates this behavior in the bundled CSS file. Like everything else, this behavior is completely customizable. The Bundle Class has an Orderer property that conforms to the IBundleOrderer interface.
Click for a larger version of this image.

Figure 6: The Bundle.Orderer Property controls how files are ordered within the bundle.

Conclusion
With each release, the ASP.NET MVC Framework gets better and better. Bundling and minification is an essential process that needs to be in every production Web app that relies on significant JavaScript and CSS resources. Out of the box, the functionality is pretty good. There are, however, some missing pieces. Fortunately, the process was designed with customization and extensibility in mind. With a little effort, it was easy to toggle minification based on whether or not the application was being run under debug mode.
One final point, this article was based on beta software. The usual disclaimer applies - this functionality may change when the product is released to manufacturing (RTM).
John V. Petersen
&

SPONSORED SIDEBAR: Learn ASP.NET MVC in a Day!

ASP.NET is one of the world’s most popular Web development environments. We can help you with all ASP.NET projects as well as related technologies, such as HTML (4 and 5), JavaScript, jQuery, CSS, AJAX, services, and many more. (Learn more from www.codemag.com/consulting.)
That’s why CODE Training is offering a full day of training in ASP.NET MVC from CODE Consultants, experts in Web development. CODE Training and EPS Software will be holding an intensive one-day lecture, June 5, 2012, on ASP.NET MVC specifically designed for developers of business applications. Learn how, when and why to use ASP.NET MVC for the best result in your projects. Only $399!
Visit www.codemag.com/training to find out a little bit more about the class, or send an e-mail to info@codemag.com for more information.


Listing 1: Custom bundler class
using System;using System.Linq;using System.Web.Optimization;
namespace MVC4BundleUI{ public class MyBundler { public static void init() { IBundleTransform jstransformer; IBundleTransform csstransformer;
#if DEBUGjstransformer = new NoTransform("text/javascript"); csstransformer = new NoTransform("text/css"); #else jstransformer = new JsMinify(); csstransformer = new CssMinify(); #endif
var bundle = new Bundle("~/Scripts/js", jstransformer);
bundle.AddFile("~/Scripts/jquery-1.6.2.js", true); bundle.AddFile("~/Scripts/jquery-ui-1.8.11.js", true); bundle.AddFile("~/Scripts/jquery.validate.unobtrusive.js", true); bundle.AddFile("~/Scripts/jquery.unobtrusive-ajax.js", true); bundle.AddFile("~/Scripts/jquery.validate.js", true); bundle.AddFile("~/Scripts/modernizr-2.0.6-development-only.js", true); bundle.AddFile("~/Scripts/AjaxLogin.js", true); bundle.AddFile("~/Scripts/knockout-2.0.0.debug.js", true);
BundleTable.Bundles.Add(bundle);
bundle = new Bundle("~/Content/css", csstransformer);
bundle.AddFile("~/Content/site.css", true);
BundleTable.Bundles.Add(bundle);
bundle = new Bundle("~/Content/themes/base/css", csstransformer);
bundle.AddFile("~/Content/themes/base/jquery.ui.core.css", true); bundle.AddFile("~/Content/themes/base/jquery.ui.resizable.css", true); bundle.AddFile("~/Content/themes/base/jquery.ui.selectable.css",true); bundle.AddFile("~/Content/themes/base/jquery.ui.accordion.css",true); bundle.AddFile("~/Content/themes/base/jquery.ui.autocomplete.css",true); bundle.AddFile("~/Content/themes/base/jquery.ui.autocomplete.css", true); bundle.AddFile("~/Content/themes/base/jquery.ui.dialog.css",true); bundle.AddFile("~/Content/themes/base/jquery.ui.slider.css", true); bundle.AddFile("~/Content/themes/base/jquery.ui.tabs.css", true); bundle.AddFile("~/Content/themes/base/jquery.ui.datepicker.css",true); bundle.AddFile("~/Content/themes/base/jquery.ui.progressbar.css",true); bundle.AddFile("~/Content/themes/base/jquery.ui.theme.css", true);
BundleTable.Bundles.Add(bundle); } }
}

Listing 2: Simplied custom bundler code using the AddDirectory() method
public class MyBundler { public static void init() { IBundleTransform jstransformer; IBundleTransform csstransformer;
#if DEBUGjstransformer = new NoTransform("text/javascript"); csstransformer = new NoTransform("text/css"); #else jstransformer = new JsMinify(); csstransformer = new CssMinify(); #endif
var bundle = new Bundle("~/Scripts/js", jstransformer); bundle.AddDirectory("~/Scripts/","*.js",true, true); BundleTable.Bundles.Add(bundle);
bundle = new Bundle("~/Content/css", csstransformer); bundle.AddDirectory("~/Content/", "*.css", true, true);
BundleTable.Bundles.Add(bundle); } }

Listing 3: NoTransform transformation Class
public class NoTransform : IBundleTransform { readonly string _contentType;
public NoTransform(string contentType) { this._contentType = contentType; }
public void Process(BundleContext context, BundleResponse response) { response.ContentType = this._contentType; } }

Listing 4: YUI Compressor transformation class
using System.IO;using System.Web.Optimization;using Yahoo.Yui.Compressor;
namespace Bundler.Utilities{ public enum contentType { javascript, css }
public class YUITransform : IBundleTransform { readonly string _contentType = string.Empty;
public YUITransform(contentType contentType) { if (contentType == contentType.css) { this._contentType = "text/css"; } else { this._contentType = "text/javascript"; } }
public void Process(BundleContext context, BundleResponse bundle) { bundle.ContentType = this._contentType;
string content = string.Empty;
foreach (FileInfo file in bundle.Files) {
using (StreamReader fileReader = new StreamReader(file.FullName)) { content += fileReader.ReadToEnd(); fileReader.Close(); }
}
bundle.Content = Compress(content); }
string Compress(string content) { if (_contentType == "text/javascript") { return JavaScriptCompressor.Compress(content); } else { return CssCompressor.Compress(content, CssCompressionType.StockYuiCompressor); } } }}

3/17/2012

Build Mobile-Friendly HTML5 Forms with ASP.NET MVC 4 and jQuery Mobile

Rachel Appel
Last month in my MSDN Magazine Web column, I covered how to get started with the latest tools for Microsoft Web development: HTML5, jQuery Mobile and ASP.NET MVC 4. In this issue, I’ll explain how to create mobile-friendly HTML5 forms in ASP.NET MVC 4 projects that also use jQuery Mobile.

Mobilized Web Project Templates in Visual Studio 2010

The MVC 4 Mobile project template in Visual Studio 2010 contains all the files and references necessary to create a mobile-friendly Web site. When you create a new MVC 4 Mobile project, you’ll notice the familiar Models, Views and Controllers folders requisite for all MVC 4 projects (mobile or not) alongside new or modified scripts in the \Scripts folder. The \Scripts folder is where you’ll find the many jQuery files that serve as an API for building mobile-friendly Web sites, in particular, the jquery.mobile-1.0b2.js file for development and its minified partner, jquery.mobile-1.0b2.min.js, for deployment.
The \Content folder contains the location for style sheets, images and design-related files. Keep in mind that the jquery.mobile-1.0b2.css style sheet defines a look and feel that specifically targets multiple mobile platforms. (See http://jquerymobile.com/gbs/ for a list of supported mobile and tablet platforms.) Much like JavaScript files, there are two style sheets: a fat version for development and a minified version for production.

Data Sources for HTML5 Forms: MVC 4 Models and ViewModels

Regardless of whether the target is mobile or desktop, HTML5 form elements map to a property of an entity in a model or a ViewModel. Because models expose varied data and data types, their representation in the user interface requires varied visual elements, such as text boxes, drop-down lists, check boxes and buttons. You can see the full set of available controls or elements at the jQuery Mobile Web site’s Form Element Gallery.
Simple forms that contain only text inputs and buttons are not the norm. Most forms have several types of data. Because of this data variety, coding and maintenance will be easier if you use a ViewModel. ViewModels are a combination of one or more types that together shape data that goes to the view for consumption and rendering.
Let’s say you want to build a quick way for users of your Web site to provide feedback. You need to collect the user’s name, the type of feedback the user wants to leave, the comment itself, and the priority of the comment—that is, whether or not it’s urgent. Figure 1 shows how the FeedbackModel class definition captures these features in simple data structures such as strings, an int, and a Boolean.
  1. public class FeedbackModel
  2. {
  3.     public string CustomerName { get; set; }
  4.     public int FeedbackType { get; set; }
  5.     public string Message { get; set; }
  6.     public bool IsUrgent { get; set; }
  7. }
Figure 1 Feedback Model
The FeedbackType property in Figure 1 is of type int, and it corresponds to the value the user selects at run time in the feedback type drop-down list defined in Figure 3.
Figure 2 contains the definition for the FeedbackViewModel, which is a combination of the FeedbackModel described in Figure 1 and the FeedbackType class (described in Figure 3).
  1. public class FeedbackViewModel
  2. {
  3.     public FeedbackModel Feedback { get; set; }
  4.     public FeedbackType FeedbackType { get; set; }        
  5.     public FeedbackViewModel()
  6.     {
  7.         Feedback = new FeedbackModel();
  8.         FeedbackType = new FeedbackType();
  9.     }
  10. }
Figure 2 Feedback ViewModel Containing the FeedbackModel and FeedbackType Properties
The use of the FeedbackType property highlights the purpose of ViewModels, which, as I mentioned earlier, is to shape disparate data sources or models together to form a single consumable source from the view, using strongly typed syntax.
While you can represent most of the data in a simple ViewModel as text boxes or check boxes, you also need to capture the type of feedback, which is a list of name-value pairs exposed in code as a more complex dictionary object. Figure 3 shows the FeedbackType class and the dictionary contained within it.
  1. public class FeedbackType
  2. {
  3.     public static SelectList FeedbackSelectList
  4.     {
  5.         get { return new SelectList(FeedbackDictionary, "Value""Key"); }
  6.     }
  7.     public static readonly IDictionary<stringint
  8.          FeedbackDictionary = new Dictionary<stringint
  9.     { 
  10.         { "Select the type ..."0 },
  11.         { "Leave a compliment"1 },
  12.         { "Leave a complaint"2 },
  13.         { "Leave some SPAM"3 },
  14.         { "Other"9 }
  15.     };
  16. }
Figure 3 FeedbackType Class, Including User Feedback Types
Now that the ViewModel is complete, the controller must pass it to the view for rendering. This straightforward code is in Figure 4 and is virtually identical to code that passes back a model.
  1. public ActionResult Feedback()
  2. {
  3.     FeedbackViewModel model = new FeedbackViewModel();
  4.     return View(model);
  5. }
Figure 4 Controller Passing the ViewModel to the View
The next step in the process is setting up the view.

Creating HTML5 Mobile Forms in ASP.NET MVC 4 Views

You use the standard Add New Item command in Visual Studio 2010 to create feedback.cshtml, the view that will host your HTML5 form. ASP.NET MVC 4 favors a development technique named convention over configuration, and the convention is to match the name of the action method (Feedback) in the controller in Figure 4 with the name of the view, that is, feedback.cshtml. You can find the Add New Item command from the shortcut menu in Solution Explorer or the Project menu.
Inside the view, various ASP.NET MVC 4 Html Helpers present components of the FeedbackViewModel by rendering HTML elements that best fit the data types they map to in the ViewModel. For example, CustomerName renders as a standard single-line text box, while the Message property renders as a text area. FeedbackType renders as an HTML drop-down list so that the user can easily select an item rather than manually enter it. Figure 5 shows that there is no lack of Html Helpers to choose from for building forms.
  1. @using (Html.BeginForm( "Results","Home")) {
  2.     @Html.ValidationSummary(true)
  3.     <fieldset>
  4.         <legend>Leave some feedback!</legend>
  5.         <div class="editor-label">
  6.             @Html.LabelFor(model => model.Feedback.CustomerName)
  7.         </div>
  8.         <div class="editor-field">
  9.             @Html.TextBoxFor(model => model.Feedback.CustomerName)
  10.             @Html.ValidationMessageFor(model => model.Feedback.CustomerName)
  11.         </div>
  12.         <div class="editor-label">
  13.             @Html.LabelFor(model => model.Feedback.FeedbackType)
  14.         </div>
  15.         <div class="editor-field">
  16.             @Html.DropDownListFor(model => model.Feedback.FeedbackType, 
  17.                  FeedbackType.FeedbackSelectList) 
  18.             @Html.ValidationMessageFor(model => model.Feedback.FeedbackType)
  19.         </div>
  20.         <div class="editor-label">
  21.             @Html.LabelFor(model => model.Feedback.Message)
  22.         </div>
  23.         <div class="editor-field">
  24.             @Html.TextAreaFor(model => model.Feedback.Message)
  25.             @Html.ValidationMessageFor(model => model.Feedback.Message)
  26.         </div>
  27.         <div class="editor-label">
  28.             @Html.LabelFor(model => model.Feedback.IsUrgent)
  29.         </div>
  30.         <div class="editor-field">
  31.             @Html.EditorFor(model => model.Feedback.IsUrgent)
  32.             @Html.ValidationMessageFor(model => model.Feedback.IsUrgent)
  33.         </div>
  34.         <p>
  35.             <input type="submit" value="Save" />
  36.         </p>
  37.     </fieldset>
  38. }
Figure 5 Html Helpers
With the ViewModel, controller and view, the form is now ready to test in the browser.

Testing the HTML Form on the Windows Phone 7 Emulator

Running a browser from Visual Studio is the easiest way to test the form, but the look and feel doesn’t behave in a very mobile-like way. For viewing the output and testing the form, the Windows Phone 7 Emulator works perfectly.
The HTML5 form displays in the Windows Phone 7 Emulator, as shown in Figure 6. You can enter a name, select a type from the drop-down list, fill in the comments and submit the form. Without modifications to the default styling provided by jQuery Mobile style sheets, the overall HTML5 form looks like the image on the left side of Figure 6. After tapping on the drop-down, the list of items looks like the image on the right side of Figure 6. Tapping a list item to select it returns the user to the form.
Interacting with the Windows Phone 7 Emulator
Figure 6 Interacting with the Windows Phone 7 Emulator
Submitting the form directs the browser to send the form information to the Home controller because of the call to the Html Helper, Html.BeginForm( "Results","Home"). The BeginForm method directs the HTTP request to the HomeController controller and then runs the Results action method, as the arguments denote.
Before the form submission process sends the HTTP Request to the server, however, client-side validation needs to happen. Annotating the data model accomplishes this task nicely. In addition to validation, data annotations provide a way for the Html.Label and Html.LabelFor helpers to produce customized property labels. Figure 7 details the entire data model with attributes for both validation and aesthetic annotations, and Figure 8 illustrates their results in the Windows Phone 7 Emulator.
  1. public class FeedbackModel
  2. {
  3.     [Display(Name = "Who are you?")]
  4.     [Required()]
  5.     public string CustomerName { get; set; }
  6.     [Display(Name = "Your feedback is about...")]
  7.     public int FeedbackType { get; set; }
  8.     [Display(Name = "Leave your message!")]
  9.     [Required()]
  10.     public string Message { get; set; }
  11.     [Display(Name = "Is this urgent?")]
  12.     public bool IsUrgent { get; set; }
  13. }
Figure 7 Complete Data Model with Annotations
Left: Data Annotation Validations; Right: Data Annotation Aesthetics
Figure 8 Left: Data Annotation Validations; Right: Data Annotation Aesthetics
You can customize the error message of the Required attribute to make the user interface friendlier. There are also many more annotations available in the System.Data.DataAnnotations namespace. If you can’t find a data annotation that fits your validation, aesthetic or security needs, inheriting from the System.Attribute class and extending it gives you that flexibility.

From the Phone to the Server Through HTTP POST

Once the user taps the submit button on the phone—and assuming the form passes validation—an HTTP POST Request is initiated and the data travels to the controller and action method designated in the Html.BeginForm method (as was shown in Figure 5). The sample from Figure 9 shows the controller code that lives in the HomeController and processes the data that the HTTP Request sends. Because of the power of ASP.NET MVC 4 model binding, you can access the HTML form values with the same strongly typed object used to create the form – your ViewModel.
  1. [HttpPost()]
  2. public ActionResult Results(FeedbackViewModel model)
  3. {
  4.     // calls to code to update model, validation, LOB code, etc...
  5.     return View(model);
  6. }
Figure 9 Capturing the HTTP POST Data in the Controller
When capturing HTTP POST data, data annotations once again assist in the task, since action methods that have no attribute stating the type of HTTP verb default to HTTP GET. 

Conclusion

Creating shiny new forms for mobile devices as well as desktops has never been easier with the partnership between ASP.NET MVC 4, jQuery Mobile and HTML5.
Next month we dig deeper into this example by collecting the feedback data and saving it back to a database using Entity Framework.

2/23/2012

Knockout Session from South Florida Code Camp

by JohnPapa.net 

I had a great time at the South Florida Code Camp last weekend presenting a Whirlwind tour of Knockout and Javascript Patterns. The rooms were small and way overpacked, but I’ll take that as a sign that the topic is popular Smile
The Knockout session is a whirlwind tour of KnockoutJS ’s features. If you like it and want to see more in depth material on Knockout, you can check out my full  course at Pluralsight titled Building HTML5 and JavaScript Apps with MVVM and KnockoutJS.
image
Here are the slides and sample code from the presentation at code camp. Thanks for attending!

7/26/2011

setInterval and setTimeout

In javascript, the two functions setInterval and setTimeout can be extremely useful and important, but using either of them in complex ways can be a confusing ordeal. In this tutorial, I'm going to try and show the range of possibilities, from the very simple, to the complex, to the 'why oh why is it working like this!?'.

So lets start out with the extremely simple - what do the setInterval and setTimeout functions do?

They are both functions attached to the window object of a web page, and they allow, in a very crude manner, a sort of 'thread-like' control.
The setTimeout call lets you tell the browser to execute a javascript call after a certain time has passed. It takes two arguments - what to execute, and how long to wait (in milliseconds). Here is an example of a very simple setTimeout call:

setTimeout("alert('hi!');", 500);
This call will execute the code alert('hi!'); after 500 milliseconds has passed.
The setInterval call has similar arguments, but instead of just executing the given code once, it executes it over and over again, using the second argument as the amount of time to wait between executions. Here is a simple example of a setInterval call:

setInterval("alert('hi!');", 500);
This call will execute the code alert('hi'); every 500 milliseconds from now until the the page it is loaded on is closed.

But if that was all you could do with these two functions, it wouldn't be very interesting, now, would it? Fortunately, that is only the tip of the iceberg.

Both of these functions return an integer id when they are called - which in and of itself is not very useful. But what these ids allow you to do is clear an interval/timeout call if you don't want it anymore. There are two companion funtions called clearTimeout and clearInterval which you can pass these ids to - and they will clear the timeout/interval associated with the id. This especially useful for setInterval, because it is probably rare that you want something on your page executing every X milliseconds for the entire time the user has the page open.

Using the functions is very simple, you can just call them like the following:

var timeoutID = setTimeout("alert('hi!');", 500);
var intervalID = setInterval("alert('hi!');", 500);
clearTimeout(timeoutID);
clearInterval(intervalID);

Ref: http://www.switchonthecode.com/tutorials/javascript-tutorial-using-setinterval-and-settimeout

7/21/2011

Some notes when write javascript

Avoid Using Eval() Function and With Statement

The eval() function executes a piece of code supplied as a string. For example, consider the eval() function call below:
eval("var myVar=100;alert(myVar);");
There is no way for the minifier tool to convert this string literal into a compact form. As a result the call will not be compacted. Similarly, using with statement also hampers the minification process.
var myVar = 100;
with(window) {
    alert(myVar);
} 
Since the minifier tool won't know whether myVar refers to the variable or to a member of window object the entire block will not be minified.

Try to Avoid Global Variables and Functions

Global variables and functions are never minified because there is a chance that they are used from some other part of the website. Consider the set of global variables and function below:
function MainFunction() {
    HelperFunction1();
    HelperFunction2();
}

function HelperFunction1() {
    alert("inside helper function 1");
}

function HelperFunction2() {
    alert("inside helper function 2");
}
Here, the functions HelperFunction1() and HelperFunction2() are used only by MainFunction() and are not used anywhere else. However, since they are in global scope, the minifier tool will not compact them. You can overcome this problem by modifying the code like this:
function MainFunction() {
    var HelperFunction1=function(){
        alert("inside helper function 1");
    }

    var HelperFunction2=function() {
        alert("inside helper function 2");
    }
    HelperFunction1();
    HelperFunction2();
}
Now, the minifier tool will compact both of the helper functions to smaller names and calls to them will also be substituted accordingly.

Use Shortcuts for Window and Document Objects

It is very common to use window and document JavaScript objects in the code. If you refer them as "window" and "document" at each and every place then you will be wasting bytes every time. Instead you can use them as shown below:
var w = window;
var d = document;
function MainFunction() {
    d.getElementById("Div1");
    w.setInterval(myCode, 1000);
}
You can even wrap frequently used methods of document object (such as getElementById) in a separate function like this:
function Get(id)
{
    return d.getElementById(id);
}
Then use the Get() function at all the places where you would have used getElementById() method.
function DoTest() {
 alert(Get("abc").id);
}