CoffeeScript Play Time and References

CoffeeScriptI’ve been meaning to play with CoffeeScript for sometime now. A few months ago, I skimmed through CoffecScript.org site and The Little Book on CoffeeScript but never actually wrote code to generated JavaScript. The other day I watched the Tekpub training on the Art of Speaking with Scott Hanselman ( the master ) in which Rob Conary challenged Scott to give a 15 minute presentation on CoffeeScript in a few hours. After listening, I was recharged to get code playtime with CoffeeScript. I leveraged JSFiddle to play with the JavaScript real-time but leveraged Visual Studio with Mindscape Web Workbench to play with CoffeeScript. Scott Hanselman talks in detail about Mindscape Web Workbench here. You can also head over to JS 2 Coffee Generator to generate some JavaScript into CoffeeScript on the fly.

I do NOT plan to introduce CoffeeScript or sell you CoffeeScript like a used car salesman! Instead, breeze through VS 2010 setup, review some code examples and provide a list of resources ( web casts, books, blogs, and tools ) to help educate and convince yourself CoffeeScript is meaningful. I will briefly explain what CoffeeScript is and list a few benefits. In a future post I will discuss what IcedCoffeeScript brings to the table.

What is CoffeeScript?

CoffeeScript is a little language that compiles into JavaScript. CoffeeScript is an attempt to expose the good parts of JavaScript in a simple way. The golden rule of CoffeeScript is: "It's just JavaScript".

Advantages of CoffeeScript

  • Safety of compiled code ( passes through JavaScript Lint )
  • JavaScript output code is readable and pretty-printed
  • Repeatability and consistency
  • Runs as fast or faster than most handwritten JavaScript

Disadvantages of CoffeeScript

  • Learning curve?
  • Difficult to debug?

Visual Studio 2010 Setup

At the time of this post version 2.0.515.19552 supports VS 2010 and has experimental support for VS 2011 IDE. To setup Visual Studio 2010 with Mindscape Web Workbench and generate your first JavaScript file from CoffeeScript follow the next steps.

  1. Download the plug-in here
  2. Ensure you are not running Visual Studio 2010. If so, close the IDE.
  3. Double click the Mindscape.WebWorkbench.Integration.10.vsix file you downloaded in step 1
  4. Open Visual Studio 2010
  5. Navigate to Tools –> Extension Manager
  6. You should see Mindscape Web Workbench.
  7. Close

Creating a *.coffee script is effortless and generating the resulting JavaScript can be done blindfolded. Here are the steps:

  1. Open Visual Studio 2010.
  2. Create a new blank solution called coffeeScript.demo
  3. Add a new ASP.NET MVC 3 project to the solution
  4. Click on the Scripts directory
  5. To add a new text file press Ctrl+Shift+A
  6. Select Text File
  7. Rename the file to demo.coffee and create
  8. In the Solution Explorer expand the demo.coffee file and observe the demo.js file
  9. Open the demo.coffee and demo.js files
  10. Paste the following code
My First CoffeeScript demo.coffee
1
 demoTask = (start, end) -> end - start
  1. Save demo.coffee file
  2. Notice demo.js now contains the code below.
My First CoffeeScript Generated to JavaScript demo.js
1
2
3
4
5
6
(function(){
  var demoTask;
  demoTask = function(start, end) {
    return end - start;
  };
})();

Now Visual Studio 2010 and Mindscape Web Workbench are setup and the IDE can now generate JavaScript from CoffeeScript we can take a look at a more complex sample.

  1. Review original JavaScript code
  2. Write in CoffeeScript
  3. Review the generated JavaScript

Original JavaScript:

The JavaScript sample below is an anonymous function called by controls that want to register standard, cookie cutter JQuery UI AutoComplete functionality. The source data and searches load the lookup date from a custom HTTP Handler named CxJsonHandler that queries a ASP.NET Web Service for lookup data based on the lookupType, lookupFilter and lookupQueryType passed in. The code leverages JQuery AJAX call to make the request and received the data. On success the JSON return is processed by mapping it to the label, value properties of the response. The remainder of the code wires up events and sets an is dirty flag when data changes by calling setIsDirtyFlagToDirty(). The original function is displayed as it exists in the code base. Next this JavaScript code will be written in CoffeeScript.

JQuery UI Setup AutoComplete Share Anonymous Function original.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
setLookupAutoComplete = function(selectorClientId, selectorIdClientId, lookupType, lookupFilter, lookupQueryType) {
      $(selectorClientId).autocomplete({
          source: function(request, response) {
              $.ajax({
                  url: "../Services/CxJsonHandler.ashx",
                  dataType: "json",
                  data: {
                      query: request.term,
                      lkupType: lookupType,
                      lkupTypeFilter: lookupFilter,
                      lkupQueryType: lookupQueryType
                  },
                  success: function(data) {
                      // If data returned no data clear it
                      if (data == null) {
                          $(selectorClientId).val("");
                          $(selectorIdClientId).val("");
                          return;
                      }
                      response($.map(data, function(item) {
                          return {
                              label: item.name,
                              value: item.id
                          }
                      }));
                  },
                  error: function(jqXHR, textStatus, errorThrown) {
                      //alert("failure - " + jqXHR + textStatus + errorThrown);
                  }
              });
          },
          minLength: 0,
          focus: function(event, ui) {
              return false;
          },
          select: function(event, ui) {
              $(selectorClientId).val(ui.item.label);
              $(selectorIdClientId).val(ui.item.value);

              setIsDirtyFlagToDirty();
              return false;
          },
          change: function(event, ui) {

              if (!ui.item) {
                  // remove invalid value, as it didn't match anything
                  $(selectorClientId).val("");
                  $(selectorIdClientId).val("");
                  setIsDirtyFlagToDirty();
                  return false;
              }

              if (isBlank(ui.item.label) && !isBlank(ui.item.value)) {
                  $(selectorIdClientId).val("");
                  alert('blank');
              }

              setIsDirtyFlagToDirty();

              return false;
          }
      });
  };

CoffeeScript:

Easy to see the amount of code has been reduced. In addition, the code has been formatted nicely making the code easier to read and understand. Another important thing to notice is there are NO semi-colons or curly braces. HURRAY! Yes, the dreaded semi-colons and curly braces will now be generated and inspected by CoffeeScript Interpretor and JavaScript Lint. This reduces, if not eliminates the crazy bugs that can take days to debug from missing semi-colons and wrongly placed or spaced curly braces.

JQuery UI Setup AutoComplete Share Anonymous Function originalAs.coffee
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
setLookupAutoComplete = (selectorClientId, selectorIdClientId, lookupType, lookupFilter, lookupQueryType) ->
  $(selectorClientId).autocomplete
    source: (request, response) ->
      $.ajax
        url: "../Services/CxJsonHandler.ashx"
        dataType: "json"
        data:
          query: request.term
          lkupType: lookupType
          lkupTypeFilter: lookupFilter
          lkupQueryType: lookupQueryType

        success: (data) ->
          unless data?
            $(selectorClientId).val ""
            $(selectorIdClientId).val ""
            return
          response $.map(data, (item) ->
            label: item.name
            value: item.id
          )

        error: (jqXHR, textStatus, errorThrown) ->

    minLength: 0
    focus: (event, ui) ->
      false

    select: (event, ui) ->
      $(selectorClientId).val ui.item.label
      $(selectorIdClientId).val ui.item.value
      setIsDirtyFlagToDirty()
      false

    change: (event, ui) ->
      unless ui.item
        $(selectorClientId).val ""
        $(selectorIdClientId).val ""
        setIsDirtyFlagToDirty()
        return false
      if isBlank(ui.item.label) and not isBlank(ui.item.value)
        $(selectorIdClientId).val ""
        alert "blank"
      setIsDirtyFlagToDirty()
      false

Generated JavaScript:

Feast your eyes on this beautiful code! The formatting, spacing, perfectly placed curly braces, semi-colons, tabs, and no extra white spaces. There is no mixed up tabbing, spacing or extra white space. This code will be perfect every time! While you could argue with the meat of the code you can not with the formatting.

JQuery UI Setup AutoComplete Share Anonymous Function newGeneratedFromCoffeeScript.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
var setLookupAutoComplete;
setLookupAutoComplete = function(selectorClientId, selectorIdClientId, lookupType, lookupFilter, lookupQueryType) {
  return $(selectorClientId).autocomplete({
    source: function(request, response) {
      return $.ajax({
        url: "../Services/CxJsonHandler.ashx",
        dataType: "json",
        data: {
          query: request.term,
          lkupType: lookupType,
          lkupTypeFilter: lookupFilter,
          lkupQueryType: lookupQueryType
        },
        success: function(data) {
          if (data == null) {
            $(selectorClientId).val("");
            $(selectorIdClientId).val("");
            return;
          }
          return response($.map(data, function(item) {
            return {
              label: item.name,
              value: item.id
            };
          }));
        },
        error: function(jqXHR, textStatus, errorThrown) {}
      });
    },
    minLength: 0,
    focus: function(event, ui) {
      return false;
    },
    select: function(event, ui) {
      $(selectorClientId).val(ui.item.label);
      $(selectorIdClientId).val(ui.item.value);
      setIsDirtyFlagToDirty();
      return false;
    },
    change: function(event, ui) {
      if (!ui.item) {
        $(selectorClientId).val("");
        $(selectorIdClientId).val("");
        setIsDirtyFlagToDirty();
        return false;
      }
      if (isBlank(ui.item.label) && !isBlank(ui.item.value)) {
        $(selectorIdClientId).val("");
        alert("blank");
      }
      setIsDirtyFlagToDirty();
      return false;
    }
  });
};

Where To Next?

In a future post I will talked about IcedCoffeeScript.

IcedCoffeeScript is a fork of CoffeeScript. It is superset of the CoffeeScript language. The iced interpreter is a drop-in replacement for the standard coffee interpreter since it will interpret all existing CoffeeScript programs.

For now review the web casts, books, blog articles, and tools reference for your convenience below.

Web Casts

Books

Blogs Articles

Tools

Comments