Master Details with Dialog in ASP.Net MVC and Unobstrusive Ajax

Today’s post explains a user interface that is not uncommon. The user interface consists of a list of items, and if the user clicks a link in the row of data for an item, a dialog window appears so the user can edit the details of the item. When the user saves their changes, the table updates itself to reflect the new changes.

I’m going to cover an approach you can use with ASP.Net MVC to enable this, and explain the aspects required for the Controller and Views that make it all hang together. I’m not going into detail about where the data comes from or what the data is. The idea here is to concentrate on the pattern – you can work out what the data for the list and details screens, respectively, is.

Controller

We’ll set up the controller first. The controller requires at least four methods:

Index method

This handles the initial interaction of the user with the screen. It’s job is to retrieve the data from whatever is the data source to display and display the “Index” View.

public ActionResult Index(){
  MyListModel model = new MyListModel{
    Data= myDataStore.GetDataAsList()             
  };

  return View(model);
}

The Record – Get – Method

This action returns a partial view via Ajax of the record to be edited. I will cover in a moment what is done on the client, but this method builds the edit View Model for the entity by first retrieving it from the data store. Note the use of the null able parameter to indicate if a new record should be created.

Also of interest is the use of the OutputCache action filter to ensure that the Ajax GET request is not cached on the client.

[OutputCache(NoStore = true, VaryByParam = "None", Duration = 0)]
public PartialViewResult MyEntity(int? id){
  DetailViewModel model = new DetailViewModel ();

  if (id.HasValue){
    model.EntityDetail = myDataStore.GetData(id.Value);
  }
  else{
    model.EntityDetail = new MyEntityDetail();
  }
  
  return PartialView("Detail", model);
}

The Record – Post- Method

This method does the update based on a POSTed model. Note how it the method has same name as the previous method, but is decorated with a [HttpPost] attribute and takes a populated entity model as a parameter. If the ModelState is valid, then it is prudent to clear the model state so that posted values are not re-displayed when rendering the view. Instead, the model is refreshed from the data store.

[HttpPost]
public PartialViewResult MyEntity(DetailViewMode model){
  if(ModelState.IsValid){
     ModelState.Clear();   
     model.EntityDetail = myDataStore.UpdateMyEntity(model.EntityDetail);
     ViewBag.Message = "Details Successfully Updated";  
  }

  return PartialView("Detail", model);
}

The partial list refresh

Once the record has been updated, the list of records needs to refresh itself. To do this, it need to make an Ajax call to the server to return a PartialView of just the table contents. That’s what this method does. Note again the use of the [OutputCache] filter to prevent Ajax request caching.

[OutputCache(NoStore = true, VaryByParam = "None", Duration = 0)]
public PartialViewResult EntityList(){
  MyListModel model = new MyListModel{
    Data= myDataStore.GetDataAsList()             
  };
  return PartialView("List", model);
}

Views

Okay, so that’s the controller covered, now lets consider the views. I’m going to use 3 views:

  1. Index – the initial view when the user goes to the list.
  2. Detail – the details view of the entity, used for creates and edits.
  3. List – the partical view of the table of entitites.

The Index View

This is very simple. It simply renders the partial list view and all the client side script that makes it all work. Aside from the comments in the script, the keys points are the hidden div for the placements of the Ajax retrieved content.

@model MyListModel
@{
    ViewBag.Title = "List of Entities";
    Layout = "~/Views/Shared/_MainLayout.cshtml";
    //render the partial view
    Html.RenderPartial("List", Model);
}

<!-- container for ajax loaded dialog content -->
<div id="ajax-content" style="display:none">

</div>


<script type="text/javascript">
//<![CDATA[
    //this function gets called when the ajax request to GET a entity detail has completed.
    //The GET request ends with the returned HTML being placed in the div with id='ajax-content'
    //A modal dialog is created. The title for the dialog is extracted from the contained fieldset legend.
    //On close, the dialog is destroyed and the content of the ajax-content div are removed
    //On Save the contained form is submitted
    function loadEntity(xhr, status) {
        $('#ajax-content').dialog({
            modal: true,
            width:600,
            title: $('#ajax-content legend').text(),
            buttons: {
                "Save": function () {
                    //submit the form
                    $('#ajax-content form').submit();
                },
                "Close": function () {
                    //remove the content, destroy the dialog
                    $(this).dialog('destroy').html('');
                }
            }
        });
    }

    //this function gets called when the contained form has been submitted via ajax
    //this results in the content INSIDE the ajax-content being replaced, however ajax-content, which is wrapped in
    //a dialog, is not replaced and so remain visible.
    //The title of the dialog is refreshed based on the contained legend.
    //The last thing this function does is makes the table 'entity-list' reload itself from the appropriate Url which points to the "EntityList" action on the controller
    function entityDetailsUpdated(responseText, status, xhr) {
        $('#ajax-content').dialog("option", "title", $('#ajax-content legend').text());          
        $('#entity-list').load( '@Url.Action("EntityList")');
    }
//]]>
</script>


The List View

This is simply a table that shows whatever properties of the entity you want, but with one of the properties being rendered as an Ajax.ActionLink. This little Microsoft extension simply leverages the jQuery Ajax stack in an unobtrusive way. You can see that I have used the AjaxOptions class to define that callback function to call when the Ajax call is complete and the element to put the returned content in, both of which are defined in the Index View.

Note the use of the additional link in the footer of the table to create a new record. In this case, no id is passed to the controller.

@model MyListModel
@{
    AjaxOptions options = new AjaxOptions
    { 
        //"loadEntity" is a javascript method defined on the Index View
        OnComplete = "loadEntity",
        //"ajax-content" is a div defined on the Index View
        UpdateTargetId = "ajax-content"
    };
}

<!-- Important to give this an Id so that it can be told to reload itself when the 
the entity is updated -->
<table id="entity-list">
  <thead>
    <tr>
      <th>
        Name
      </th>
          .........            
    </tr>
  </thead>
<tbody>
@foreach (var entity in Model) {           
    <tr>
       <td>
            @Ajax.ActionLink(entity.Name, "MyEntity", new { id = entity.EntityID }, options)
       </td>
        ......
     </tr>
 }
  </tbody>
<tfoot>
  <tr>
    <td colspan="4">
        @Ajax.ActionLink("New Entity", "MyEntity", options)
    </td>
  </tr>
</tfoot>
</table>


The Details View

This is the edit form, and it will display in a modal dialog all going well. The key points are

  • The use of an id for the form, so that it can be submitted when the Save button is clicked.

  • the use of the Ajax.BeginForm to apply unobtrusive Ajax enabling of the form and the corresponding AjaxOptions,
  • the use of a hidden legend in the fieldset, the text of which you might recall is extracted when and used as the dialog title,
  • the setting of unobtrusive validations using script, because Ajax loaded content does not have this happen automagically
@model DetailViewModel
@{
  AjaxOptions options = new AjaxOptions{
    //always post
    HttpMethod = "post",
    //replace the existing content in the "ajax-content" element
    InsertionMode = InsertionMode.Replace,
    //defined in the Index view
    UpdateTargetId = "ajax-content",
    //the callback, defined in the Index view
    OnSuccess = "entityDetailsUpdated"        
  };    
}

@using (Ajax.BeginForm("MyEntity", null, options, new { id = "entitydetails" }))
{
  <fieldset>
    <legend style="display:none">Entity Details - @Model.Name</legend>
    @if (ViewBag.Message != null){ 
       <span class="update-message">@ViewBag.Message</span>
    }      
    @Html.ValidationSummary(true)
    <ol class="formFields">
      <li>
         @Html.EditorFor(m => m.EntityDetail.Name)
      </li>
      .......
    </ol>
    @Html.HiddenFor(m => m.EntityDetail.EntityID)
  </fieldset>  
    
  <script type="text/javascript">
    $(function () {
       $.validator.unobtrusive.parse('#entitydetails');            
     });
  </script>
}

Conclusion

This post has demonstrated how to achieve the user interface pattern for master-Details views with dialogs using ASP.Net MVC, jQuery and unobtrusive Ajax. The same effects can be created using explicit script of course, but the unobtrusive Ajax extensions are a time saver and make your views more succinct.


kick it on DotNetKicks.com

Posted in .Net, Ajax, ASP.Net MVC, jQuery | Tagged , , | 3 Comments

Accessing Embedded Resources from Razor Views in ASP.Net MVC

In razor, there is no access to the ClientScriptManager so there is no readily available method of using that class’s useful GetWebResourceUrl method to retrieve embedded resources. There are few techniques for synthesizing the functionality, revolving around the reflection of the AssemblyResourceLoader class which is all fine and well unless the application trust level prohibits reflection of non-public members. A simpler and pragmatic method is to have a partial view of the old ascx variety, and have it access the ClientScript manager of it’s Page property as below:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<dynamic>" %>
<script 
     src="<%=Page.ClientScript.GetWebResourceUrl(typeof(Page), "WebForms.js")%>" 
     type="text/javascript"></script>

Note I’m referencing WebForms.js because I’m momentarily insane. I wouldn’t recommend it in practice !! ;-). To include this web resource in a razor layout page is the same as for any partial view:


<head>
    <title>@ViewBag.Title</title>
    <link href="@Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" />
    <script 
        src="@Url.Content("~/Scripts/jquery-1.5.1.min.js")" 
        type="text/javascript"></script>
    <!-- render using as ascx control to access the client script manager -->
    @{Html.RenderPartial("WebResources");}
</head>

And that’s all there is to it. Using this technique enable to continue using embedded resources from within your razor views.

Posted in Razor | Tagged , | 1 Comment

Localization of Dates in ASP.Net MVC

Introduction

It is a somewhat inconvenient truth that users of your web site are everywhere but they don’t all talk the same language or even do simple things like read dates in the same way. ASP.Net prov ides rich support for globalization. This post covers the localization of dates, the different treatment ASP.Net applies to dates received in a QueryString to those in posted fields and provides some techniques to mitigate any issues caused by this different treatment.

ASP.Net treats Dates in URL’s different to POST fields

This came as a surprise to me. When ASP.MVC binds values from POSTed fields, it applies the current culture, but when it binds values from the URL (querystring) is uses the Invariant Culture.

This can result in unpleasant effects, particularly if like me (programming in Australia) want dates in the format day-month-year, and not the invariant month-day-year.

Say you had a form with a input field for dates. If the user entered ‘14/5/2011’ and the form was submitted via GET instead of POST, MVC would complain that this was not a valid date. If you submit the form via POST, MVC would bind the date correctly.

I wrote to Phil Haack about this:

Hi Phil,I noticed this one today. I’m in Australia (en-AU), so it common to use dates of the form dd/mm/yyyy.When these fields are POSTed, the values are as expected, because the ValueProviderResult is being constructed with the CurrentCulture out of the Mvc.FormCollection.But when the string is submitted via GET, the NameValueProvider is creating a ValueProviderResult with the Invariant culture, which is different to the current culture, and it doesn’t believe that 29/4/2011 is a valid date (29 April 2011). Most upsetting !

He replied thus

Yeah. We made a conscious choice that values pulled from the URL would be culture invariant. The reason is that URLs must be uniform. So if I send you the URL, it shouldn’t change its meaning whether the person clicking it is in AU or in US.

I can’t say I’m convinced as to his reasoning. It kind of assumes that URL’s are static and only accessed by ‘clicking’. But a form submitted via GET is a totally different interaction to a mere click. This logic more or less requires unless the server current culture somewhat reflects the invariant culture (ie you’re in the US) you should POST your forms. Consider the following simple page:

@model TestDates.Models.HomeModel
<html>
<head>
    
    <link rel="stylesheet" type="text/css" href="@Url.Content(" content ~ site.css?)?>
    <script src="@Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"></script>


@using (Html.BeginForm("Index", "Home", FormMethod.Get))
{ 
    @Html.ValidationSummary(true)
    @Html.LabelFor(m =&gt; m.SubmissionDate);    
    @Html.TextBoxFor(m =&gt; m.SubmissionDate, new { type = "date" })
    @Html.ValidationMessageFor(m =&gt; m.SubmissionDate);
    
    <input value="submit" type="submit">
}


Assuming that using a cultre with a date format dd/MM/yyyy, if you fire up this page and enter a date of say ’14/5/2010′, you will get an error from the server:”The value ’14/5/2010′ is not valid for SubmissionDate”. Not ideal!! This is a bit of a restriction but there is a workaround. You need to hook into the form submit event, get the URL the form was going to send, including it’s serialized field information and manually find and replace date fields with their equivalent invariant values. Then manually submit the form and cancel the default event. This is done using the script below:

<script type="text/javascript">
    $('form').submit(function (e) {
        //serialize the form
        var data = $(this).serialize();
	//find the url that the form was going to submit itself to
        var url = $(this).attr('action');

	//now replace every instance of a date with the equivalent ISO-8601 value
        data = data.replace(/(\d{1,2})%2F(\d{1,2})%2F(\d{4})/g, "$3%2F$2%2F$1");

	//append the url and change the window location
        if (url.match(/\?/)) {
            window.location.href = url + '&amp;' + data;
        } else {
            window.location.href = url + '?' + data;
        }

	//prevent the default action
        e.preventDefault();
    });
</script>

If you run this and submit, then the date will be parsed correctly. However a problem exists – when the date is displayed to the user, it is in the format posted to the server, so although the user typed dd/MM/yyyy, MVC saw yyyy/MM/dd in the query string and this is the format returned to the user. To get around this, you need to ensure that the users local or preferred culture is automatically set from the user’s browser by setting the following web.config element:

 <system.web>
    <globalization responseEncoding="UTF-8" 
                       requestEncoding="UTF-8" 
                       culture="auto" 
                       uiCulture ="auto" />
	.....
 </system.web>

This will result in output to the browser of, for example, dd/MM/yyyy for en-AU, MM/dd/yyyy for en-US and YYYY/MM/dd for ja-JP.

The problem still remains in that I want the date to come back to the browser in an invariant manner, so I’m going to modify my submit script to take into the current culture and always submit the date in yyyy/mm/dd format – ISO-8601 format. But because the relative positions of date, months and years can change between cultures, I need to work out the positions before applying the respective replacement regex. To do this, I create a test date and format it to a string in the current UI Culture and test what the first element is. That tells me whether the date or month or year comes first. I can then render the appropriate regex accordingly.So instead of:


data = data.replace(/(\d{1,2})%2F(\d{1,2})%2F(\d{4})/g, "$3%2F$2%2F$1");

I need to use some Razor C# when rendering the script block as follows:


....//following on previous script
@{        
  //create a known date 
  string testDate = new DateTime(2000, 10, 30).ToString("d");

  //replace the known values for years, months and days 
  //with the replacement regex expressions
  string dateRegex = testDate.Replace("2000", @"(\d{4})")
     .Replace("10", @"(\d{1,2})").Replace("30", @"(\d{1,2})").Replace("/", "%2F");

  //see if the produced date starts with the date component
  if(testDate.StartsWith("30")){
    @:data = data.replace(/@dateRegex/g, "$3%2F$2%2F$1");                           
  }
  //see if it starts with the month component
  else if(testDate.StartsWith("10")){
    @:data = data.replace(/@dateRegex/g, "$3%2F$1%2F$2");
  }  
  //it starts with the year component so no work to be done
}

....//continuing on with the script

Obviously you can extend the logic to test for date culture formats such as yyyy/dd/MM or dd/yyyy/MM (if such cultures exist) but I hope you get the point.

Localization and jQuery datepicker

It is worth noting how to switch the jquery datepicker localization. It’s simply a matter of dynamically setting the localization js as follows:

<head>
    <title>@ViewBag.Title</title>
    <link href="@Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" />
    <link href="../../Content/themes/base/jquery.ui.all.css" rel="stylesheet" type="text/css" />
    <script src="@Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"></script>
    <script src="../../Scripts/jquery-ui-1.8.11-min.js" type="text/javascript"></script>
    
    <!-- set the localization file based on the current culture -->
    <script src="../../Scripts/jquery.ui.datepicker-@(UICulture).js" type="text/javascript"></script>
</head>

Conclusion

This post has demonstrated the vagaries of localizing dates using ASP.Net MVC, and presented a few methods to provide a consistent date experience to the user, regardless of their culture.

Posted in ASP.Net MVC, jQuery, Razor | Tagged , , , | 1 Comment

Custom Unobstrusive Jquery Validation in ASP.Net MVC 3 using DataAnnotationsModelValidatorProvider

Introduction

In a previous post I covered the use of Custom Unobrusive Validation in ASP.Net MVC using the IClientValidatable. The use of this interface may not always be possible, for example if the validation attribute is defined in an assembly that cannot reference the MVC assembly, or such a reference makes no sense. Under these circumstances, there is another approach to take and that is to use adapters to help the MVC assign the client side validation to apply for a given validation attribute.

Server side code

I’ll use the same example as last time, that is a check sum validator for Australian Business and Company Numbers, but in this case I will not be implementing IClientValidatable.

public abstract class CheckSumNumberAttribute : ValidationAttribute{                       

  private string checkSumType;

  protected CheckSumNumberAttribute(string checkSumType){
    this.checkSumType = checkSumType;
  }

  public string CheckSumType{
    get {return checkSumType;}
  }
}

The implementations of two concrete classes AustralianBusinessNumberAttribute and AustralianCompanyNumberAttribute remain the same.

public class AustralianBusinessNumberAttribute : CheckSumNumberAttribute{
  private static int[] ABN_WEIGHT = { 10, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19 };
  private static Regex ABNRegex = new Regex("\\d{11}");

  public AustralianBusinessNumberAttribute() : base("abn") { }

  public override bool IsValid(object val){
    string ABN = val as string;
    bool valid = false;
    if (ABN != null){
      ABN = ABN.Replace(" ", "").Trim();
    }

    if (string.IsNullOrEmpty(ABN)){
      return true;
    }

    if (!ABNRegex.IsMatch(ABN)){
      return false;
    }

    int sum = 0;
    try{
      for (int i = 0; i < ABN_WEIGHT.Length; i++){
        // Subtract 1 from the first left digit before multiplying against the weight
        if (i == 0){
          sum = (Convert.ToInt32(ABN.Substring(i, 1)) - 1) * ABN_WEIGHT[i];
        }else{
          sum += Convert.ToInt32(ABN.Substring(i, 1)) * ABN_WEIGHT[i];
        }
      }
      valid = (sum % 89 == 0);
    }
    catch{
      valid = false;
    }
    return valid;
  }
}


public class AustralianCompanyNumberAttribute : CheckSumNumberAttribute{
  private static int[] ACN_WEIGHT = { 8, 7, 6, 5, 4, 3, 2, 1 };
  private static Regex ACNRegex = new Regex("\\d{9}");

  public AustralianCompanyNumberAttribute(): base("acn"){}

  public override bool IsValid(object val){
    string ACN = val as string;
    bool valid = false;

    if (ACN != null){
      ACN = ACN.Replace(" ", "").Trim();
    }

    if (string.IsNullOrEmpty(ACN)){
      return true;
    }

    if (!ACNRegex.IsMatch(ACN)){
      return false;
    }

    int remainder = 0;
    int sum = 0;
    int calculatedCheckDigit = 0;

    try{
      // Sum the multiplication of all the digits and weights
      for (int i = 0; i < ACN_WEIGHT.Length; i++){
        sum += Convert.ToInt32(ACN.Substring(i, 1)) * ACN_WEIGHT[i];
      }

      // Divide by 10 to obtain remainder
      remainder = sum % 10;

      // Complement the remainder to 10
      calculatedCheckDigit = (10 - remainder == 10) ? 0 : (10 - remainder);

      // Compare the calculated check digit with the actual check digit
      valid = (calculatedCheckDigit == Convert.ToInt32(ACN.Substring(8, 1)));
    }
    catch{
      valid = false;
    }
    return valid;
  }
}

Without the IClientValidatble interface, we need to create a “buddy” class of type DataAnnotationsModelValidator<TValidationAttribute> that MVC will use to create the data-val information for a given validator.

public class CheckSumValidator : 
  DataAnnotationsModelValidator<CheckSumNumberAttribute>{
  private string errorMessage;
  private string checkSumType;

  public RelatedDatesValidator(
      ModelMetadata metadata, ControllerContext context, CheckSumNumberAttribute attribute)
    : base(metadata, context, attribute){
     this.errorMessage = attribute.FormatErrorMessage(metadata.DisplayName);
     this.checkSumType = "checksum";
  }

  public override IEnumerable<ModelClientValidationRule> GetClientValidationRules(){
    var rule = new ModelClientValidationRule{
      ErrorMessage = this.errorMessage,
      ValidationType = this.validationType
    };

    rule.ValidationParameters.Add("checksumtype", checkSumType);
    yield return rule;
  }
}

Having defined the adapter class, it is neccesary to register the adapter with the DataAnnotationsModelValidatorProvider for the validation attribute. Global.asax is a good place to do this.

protected void Application_Start(){
    .....
  DataAnnotationsModelValidatorProvider
     .RegisterAdapter(
         typeof(CheckSumNumberAttribute>), 
         typeof(CheckSumValidator));
    .....
}

Client side code

The javascript required for the client side validation also remains the same as per the previous post, but here is it again for completeness.

var Xhalent = Xhalent || {};

Xhalent.validateABN = function (value) {

  value = value.replace(/[ ]+/g, '');

  if (!value.match(/\d{11}/)) {
    return false;
  }

  var weighting = [10, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19];

  var tally = (parseInt(value.charAt(0)) - 1) * weighting[0];

  for (var i = 1; i < value.length; i++) {
    tally += (parseInt(value.charAt(i)) * weighting[i]);
  }

  return (tally % 89) == 0;
};

Xhalent.validateACN = function (value) {
  value = value.replace(/[ ]+/g, '');

  if (!value.match(/\d{9}/)) {
    return false;
  }

  var weighting = [8, 7, 6, 5, 4, 3, 2, 1];
  var tally = 0;
  for (var i = 0; i < weighting.length; i++) {
    tally += (parseInt(value.charAt(i)) * weighting[i]);
  }

  var check = 10 - (tally % 10);
  check = check == 10 ? 0 : check;

  return check == parseInt(value.charAt(i));
};

//get reference to global jquery validator object and addMethod named 'xhalent_checksum'
$.validator.addMethod("xhalent_checksum", function (value, element, checksumtype) {
  if (value == null || value.length == 0) {
    return true;
  }

  if(checksumtype == 'abn') {
    return Xhalent.validateABN(value);
  }else if (checksumtype == 'acn') {
    return Xhalent.validateACN(value);
  }
});

//register the method with the unobtrusive validator library
$.validator.unobtrusive.adapters.addSingleVal('checksum', 'checksumtype', 'xhalent_checksum');

Of course, my caveats about placing this script after the dependant javascript libraries have been loaded still apply.

Conclusion

This post have demonstrated how to use Custom Unobstrusive Jquery Validation in ASP.Net MVC 3 using DataAnnotationsModelValidatorProvider instead of IClientValidatable. This is a suitable solution where it is not possible to decorate an attribute the the IClientValidatable interface or it is inappropriate to reference the MVC library from the assembly the validation attribute is defined in.

Posted in ASP.Net MVC, jQuery | Tagged | 1 Comment

Javascript Closures

Introduction

Following on from my previous article on javascript object creation and objects, arrays and associative arrays, I am now going to cover the concept of call-scope and closures in JavaScript.

Understanding scopes

In common with most languages, JavaScript has the concept of scope. Scope defines what objects are visible to a body of code at runtime. In JavaScript script the variables in scope are those in scope at the time the function was created or assigned. Variables defined in the global scope are visible to all code so long as the variable or object has been declared prior to the code in question:

 
var x = 1;

function sumFunc(y)
{   
    alert(x+y);
}

sumFunc(3);

//the value of x is visible within the function sunFunc().

JavaScript code is run in the context of a call object, which contains references to all accessible variables. Each new function or frame results in a new call object being chained onto the previous (parent) one, with the properties of the parent scope being available in the child scope. Additionally, any variables declared within the new function, and any parameters, will be properties on the child scope. If a child scope defines variables or arguments that have the same name as a property of the parent scope, they will hide the parent scope
s instance.

Examining what is going on above, when sumFunc is called, the global scope contains x. The child scope has inherited the property ‘x’ and added a new property ‘y’ which was in the parameters. When the function ends, there will be no more references to the child scope and it will be disposed of by the garbage collection. The value ‘y’ will not be available to any code. Consider if we change the code slightly:

 
var x = 1;

function sumFunc(y)
{   
    return function(){alert(x+y);};
}

var f1 = sumFunc(3);
var f2 = sumFunc(4);

f1();
f2();

If you run this code, you will get 4 and 5 displayed, respectively. What is happening is that each invocation of sumFunc results in a new instance of the nested function being created in the current scope, with their unique value of the parameter ‘y’. Exiting the function has not led to the scope being destroyed because the nested function in it’s construction attains a reference to the current scope.

Where closures are interesting is that although JavaScript does not have the concept of private variables, the use of closures can synthesize private members successfully. Consider the following script. I want to create a function that returns the next number whenever it is called.

I create a function that defines a local variable iNext and return from the function a nested function that refers back to iNext. Any function I create in this child scope will always be able to reference the value of iNext. Now when uniqueID is called, the function can reference the variable iNext because it was in scope when the function was created (it doesn’t matter if it is in scope when the function is called).

 
var uniqueID = (function(){
    var iNext = 0;   
    return function(){return iNext++;};
})();

alert(uniqueID());
alert(uniqueID());
alert(uniqueID());
alert(uniqueID());

The really interesting point is that iNext is not programmatically accessible in code. This technique can be extended to synthesize private functions. In the following script the function getSquare is not accessible through code once the self-executing function has run.

 
var uniqueID = (function(){
    var iNext = 0;   
    var iPower = 0;
    function getSquare(){
        return Math.pow(iNext,iPower);
    }
    
    return function(){return getSquare(iNext+=2, iPower++);};
})();

alert(uniqueID());
alert(uniqueID());
alert(uniqueID());
alert(uniqueID());


The closure of a function is evaluated when the function is assigned to a variable. Consider the following code. When the prototype method area is assigned to the newly created object, ‘this’ is in scope and is the object being constructed. When the function is copied into a global variable, the value of ‘this’ is evaluated again and this time it is the global window object, which does not have a value for width or height.

 
function Rect(width,height){
  this.width = width;
  this.height = height;
};

Rect.prototype = {
  area:function(){
      return this.width * this.height;     
   }
};

//create a new rect object
var rect= new Rect(10,5);

//this will output 50
alert(rect.area());

var copyOfArea = rect.area;

//this will alert NaN
alert(copyOfArea());

If we were to add two global variables width and height to the global window object, then copyOfArea would be the product of those two numbers.

It can be seen now why it is necessary to prefix all calls to properties and function for an object with the ‘this’ keyword. At the time of construction, ‘this’ is the object being constructed and all the properties relate to that instance only. That is how properties and function make up a javscript object – through the shared call context when the object is constructed.

Be aware it is important to remember that when coding event handlers that the value ‘this’ is not taken for granted. Consider the following script.

 
function MyObj(){
  this.SpecialName = "myobj";
 
    jQuery('#someButton').click(function(){        
        alert(this.SpecialName);
    });
};

var r = new MyObj();

If a button with Id “someButton” was clicked, the value of this.SpecialName would be undefined. That is because the value of “this” is different to the value of “this” when the object was created.

The correct approach for referencing an object from within a delegated function is take a local reference to “this” and have the function use it instead as below:

 
function MyObj(){
  this.SpecialName = "myobj";
   var _this = this;
    jQuery('#someButton').click(function(){        
        alert(_this.SpecialName);
    });
};

var r = new MyObj();

Conclusion

This post has covered the basics of closures in JavaScript. It was shown that functions are a combination of both the their code and the context or scope in which they are called. Interesting closures can be created by returning nested functions from functions containing local variables or methods, and in doing do private members can be synthesized. It is important to keep in mind how scopes can result in the value of “this” being overwritten in event handlers, and a safe approach under these circumstances is refer to a local reference of the “this” object prior to declaring the event handler.

Posted in Javascript | Tagged , | 1 Comment