Skip to main content

By clicking Submit, you agree to the developerWorks terms of use.

The first time you sign into developerWorks, a profile is created for you. Select information in your developerWorks profile is displayed to the public, but you may edit the information at any time. Your first name, last name (unless you choose to hide them), and display name will accompany the content that you post.

All information submitted is secure.

  • Close [x]

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerworks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

By clicking Submit, you agree to the developerWorks terms of use.

All information submitted is secure.

  • Close [x]

Your first cup of CoffeeScript, Part 3: Using CoffeeScript on the client

Michael Galpin, Software Engineer, Google
Michael Galpin's photo
Michael Galpin is a software engineer at Google. He is a co-author of the book Android in iPractice and a frequent contributor to developerWorks. For a sneak peek at what he's up to next, check out his blog or follow him on Twitter @michaelg or Google+ Michael Galpin.

Summary:  This series explores the popular CoffeeScript programming language, which is built on top of JavaScript. CoffeeScript compiles into JavaScript that is efficient and consistent with many best practices. You can run this JavaScript in a web browser or use it with technologies such as Node.js for server applications. Part 1 of this series explained how to get started with CoffeeScript and explained the perks for developers. Part 2 described how to use CoffeeScript to solve several programming problems. This article explains how to create a complete application using CoffeeScript.

View more content in this series

Date:  14 Feb 2012
Level:  Intermediate PDF:  A4 and Letter (339KB | 29 pages)Get Adobe® Reader®
Also available in:   Japanese

Activity:  13952 views
Comments:  

Introduction

CoffeeScript is a new programming language built on top of JavaScript. CoffeeScript offers a clean syntax that should appeal to anyone who likes Python or Ruby, and it also provides many functional programming features inspired by languages such as Haskell and Lisp.

In Part 1 of this series, you learned about the benefits of using CoffeeScript instead of using just JavaScript. You set up the development environment and ran scripts. In Part 2, you explored the CoffeeScript programming language by trying many of the features while solving mathematical problems.

In this article, you create a sample CoffeeScript application. Both the client-side and server-side code will be written completely in CoffeeScript. You can also download the source code used in this article.


Search powered by CoffeeScript

Frequently used abbreviations

  • JSON: JavaScript Object Notation
  • UI: User interface

The sample application that you'll create lets the user enter a search term, searching both Google and Twitter, and then display the combined results. The client side of the application gets the data the user entered and sends it to the server for results. When the results are returned from the server, the client side creates UI elements for the results and displays them on the screen. For now, don't worry about how the server side works.

Start by defining the data model for the application. The application will display search results, so define a SearchResult class. Listing 1 shows the definition.


Listing 1. Base SearchResult class

class SearchResult
    constructor: (data) ->
        @title = data.title
        @link = data.link
        @extras = data
    
    toHtml: -> "<a href='#{@link}'>#{@title}</a>"
    toJson: -> JSON.stringify @extras

The SearchResult class is rather simple. It:

  • Starts with a constructor that will define two member variables: title and link.
  • Looks for these two values in the data object that is passed to the constructor.
  • Stores the rest of the data passed to a member variable called extras.

    This will be convenient because you know you'll have two different types of search results in the application (those from Google and those from Twitter).

  • Defines two methods for the SearchResult class:
    • toHtml, which creates a simple HTML string out of the SearchResult instance, taking advantage of CoffeeScript's string interpolation.
    • toJson, for turning the SearchResult object into a JSON string.

The class in Listing 1 provides the basic features of a search result. You'll be getting much more data from search results from both Google and Twitter. Model this by creating subclasses for each type of search result. Listing 2 shows the type of search result from Google.


Listing 2. GoogleSearchResult class

class GoogleSearchResult extends SearchResult
    constructor: (data) ->
        super data
        @content = @extras.content
    toHtml: ->
        "#{super} <div class='snippet'>#{@content}</div>"

Listing 2 shows just how easy object-oriented programming is in CoffeeScript. GoogleSearchResult extends the base SearchResult class from Listing 1. Its constructor calls the constructor of the superclass. If you have ever done class-style inheritance in JavaScript, then you know how tricky this can be. Listing 3 shows the generated JavaScript.


Listing 3. GoogleSearchResult JavaScript

GoogleSearchResult = (function() {
  __extends(GoogleSearchResult, SearchResult);
  function GoogleSearchResult(data) {
    GoogleSearchResult.__super__.constructor.call(this, data);
    this.content = this.extras.content;
  }
  GoogleSearchResult.prototype.toHtml = function() {
    return "" + GoogleSearchResult.__super__.toHtml.apply(this, arguments) 
+ " <div class='snippet'>" + this.content + "</div>";
  };
  return GoogleSearchResult;
})();

To call the constructor of the superclass, you must keep an instance of the superclass in the __super__ variable (the name could be anything), and then explicitly call the constructor function. Going back to Listing 2, you can see how much easier this is in CoffeeScript. Notice that the example defined a new instance variable called content in the GoogleSearchResult class. This is basically a snippet of HTML from the web page that the search result points to. It should not be surprising that the GoogleSearchResult has this but the base class does not. Finally, notice the override of the toHtml method. The example uses the superclass's toHtml method but also appends an extra div with the content snippet. Look at Listing 3 again to see how this call to the superclass's toHtml method is accomplished. Because you have a GoogleSearchResult subclass, you need a TwitterSearchResult subclass as well, as shown in Listing 4.


Listing 4. TwitterSearchResult class

class TwitterSearchResult extends SearchResult
    constructor: (data) ->
        super data
        @source = @extras.from_user
        @link = "http://twitter.com/#{@source}/status/#{@extras.id_str}"
        @title = @extras.text
    toHtml: ->
        "<a href='http://twitter.com/#{@source}'>@#{@source}</a>: #{super}"

The TwitterSearchResult class follows the same pattern as the GoogleSearchResult class in Listing 2. Its constructor leverages the constructor of its superclass. It also:

  • Defines its own member variable called source.
  • Constructs the link member variable using a string template and its member variables.
  • Resets the title member variable to a different field from the input data.
  • Overrides the toHtml method of the superclass, appending a link to the user who created the tweet.

Once again, CoffeeScript's string interpolation makes it easy to use the superclass's toHtml method when creating a new one. To call the superclass's toHtml method, you simply call super. You might be tempted to call super.toHtml instead, but there is no need and doing so would actually cause an error. CoffeeScript implies that you want to call the same method on the superclass, making your life just a bit easier.

You now have the data structures that the application will need, and you can begin writing some of the client-side logic. It would be much easier to test the code with a working back end. Because there's not one, let's use the next best thing: mock data.


Using mock data

When building a client-server application like a modern web application, it often makes sense to create the shared interface where the two parts of the application meet and then create mock data. This lets you develop the client and server portions of the application in parallel. The approach works especially well with CoffeeScript because you can use the same programming language on both the client and server. Listing 5 shows mock search results from Google.


Listing 5. Mock Google search results

mockGoogleData = [
        GsearchResultClass:"GwebSearch",
        link:"http://jashkenas.github.com/coffee-script/",
        url:"http://jashkenas.github.com/coffee-script/",
        visibleUrl:"jashkenas.github.com",
        cacheUrl:"http://www.google.com/search?q\u003dcache:nuWrlCK4-v4J:jashkenas
.github.com",
        title:"\u003cb\u003eCoffeeScript\u003c/b\u003e",
        titleNoFormatting:"CoffeeScript",
        content:"\u003cb\u003eCoffeeScript\u003c/b\u003e is a little language that 
compiles into JavaScript. Underneath all of   those embarrassing braces and 
semicolons, JavaScript has always had a \u003cb\u003e...\u003c/b\u003e"
    ,
        GsearchResultClass:"GwebSearch",
        link:"http://en.wikipedia.org/wiki/CoffeeScript",
        url:"http://en.wikipedia.org/wiki/CoffeeScript",
        visibleUrl:"en.wikipedia.org",
        cacheUrl:"http://www.google.com/search?q\u003dcache:wshlXQEIrhIJ
:en.wikipedia.org",
        title:"\u003cb\u003eCoffeeScript\u003c/b\u003e - Wikipedia, the free 
encyclopedia",
        titleNoFormatting:"CoffeeScript - Wikipedia, the free encyclopedia",
        content:"\u003cb\u003eCoffeeScript\u003c/b\u003e is a programming language 
that transcompiles to JavaScript. The   language adds syntactic sugar inspired by 
Ruby, Python and Haskell to enhance \u003cb\u003e...\u003c/b\u003e"
    ,
        GsearchResultClass:"GwebSearch",
        link:"http://codelikebozo.com/why-im-switching-to-coffeescript",
        url:"http://codelikebozo.com/why-im-switching-to-coffeescript",
        visibleUrl:"codelikebozo.com",
        cacheUrl:"http://www.google.com/search?q\u003dcache:VDKirttkw30J:
codelikebozo.com",
        title:"Why I\u0026#39;m (Finally) Switching to \u003cb\u003eCoffeeScript
\u003c/b\u003e - Code Like Bozo",
        titleNoFormatting:"Why I\u0026#39;m (Finally) Switching to CoffeeScript - 
Code Like Bozo",
        content:"Sep 5, 2011 \u003cb\u003e...\u003c/b\u003e You may have already heard
about \u003cb\u003eCoffeeScript\u003c/b\u003e and some of the hype surrounding it
but you still have found several reasons to not make the \u003cb\u003e...
\u003c/b\u003e"   
]

It's evident that even mock data is easier to create with the simple syntax of CoffeeScript. The example shows object literals in CoffeeScript. Listing 5 is an array. Extra indentation is used to indicate an object, and each property of the object is indented again. This code compares favorably to JSON. The whitespace takes the place of curly braces. They are like JavaScript literals, where the properties are not in quotation marks. With JSON these properties have to be quoted as well.

Listing 6 shows similar mock data for Twitter search results.


Listing 6. Mock Twitter search results

mockTwitterData = [
        created_at:"Wed, 09 Nov 2011 04:18:49 +0000",
        from_user:"jashkenas",
        from_user_id:123323498,
        from_user_id_str:"123323498",
        geo:null,
        id:134122748057370625,
        id_str:"134122748057370625",
        iso_language_code:"en",
        metadata:
            recent_retweets:4,
            result_type:"popular"
        profile_image_url:"http://a3.twimg.com/profile_images/1185870726/gravatar
_normal.jpg",
        source:"<a href="http://itunes.apple.com/us/app/twitter/id409789998?mt
=12&quot; rel="nofollow">Twitter for Mac</a>",
        text:""CoffeeScript [is] the closest I felt to the power I had twenty 
years ago in Smalltalk" - Ward Cunningham (http://t.co/2Wve2V4l) Nice.",
        to_user_id:null,
        to_user_id_str:null
]

The mock data in Listing 6 is similar to the mock data in Listing 5, but with the Twitter-specific fields. Now you just need to create an interface that returns this mock data. Listing 7 shows another class that does just that.


Listing 7. A mock search engine class

class MockSearch
    search: (query, callback) ->
        results = 
            google: (new GoogleSearchResult obj for obj in mockGoogleData)
            twitter: (new TwitterSearchResult obj for obj in mockTwitterData)
        callback results

The MockSearch class has a single method called search. It takes two parameters: query to use for the search, and a callback function. MockSearch returns results quickly, but a real search will need to go over the network to talk to the servers. To handle this in JavaScript, and to make sure you don't cause the UI to freeze up, you would typically use a callback function.

The next step creates an object called results. You're again using the object literal syntax of CoffeeScript. The results object has two fields: google and twitter. The values of each field are expressed using an array comprehension. The expression will create an array of the appropriate type of SearchResult (GoogleSearchResult for Google and TwitterSearchResult for Twitter). Finally, the callback function is invoked with the results object passed to it.

The mock search is working, so you're ready to write the client-side code related to the UI.


Bringing it all together in the browser

Before glueing the UI to the application code, first take a look at the UI you'll be using. Listing 8 shows a very simple web page.


Listing 8. CoffeeSearch web page

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
   "http://www.w3.org/TR/html4/strict.dtd">

<html lang="en">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>CoffeeSearch</title>
    <script type="text/javascript" src="search.js"></script>
</head>
<body>
    <div>
        <label for="searchQuery">Keyword:</label>
        <input type="text" name="searchQuery" id="searchQuery"></input>
        <input type="button" value="Search" onclick="doSearch()"/>
    </div>
    <div class="goog" id="gr"/>
    <div class="twit" id="tr"/>
</body>
</html>

The web page above has a basic form for entering a keyword and passing it to a search engine. It has two sections defined and ready for search results to be added to them. The web page has no JavaScript defined in it. Instead, all of it is in a file called search.js, which will be the compiled version of the CoffeeScript. Notice that when the search button is clicked, a function called doSearch is invoked. This function must be in the search.js file; it's the only thing in the search.js file that you haven't seen yet. Listing 9 shows the definition in CoffeeScript.


Listing 9. Web page's doSearch function

@doSearch = ->
    $ = (id) -> document.getElementById(id)
    kw = $("searchQuery").value
    appender = (id, data) ->
        data.forEach (x) -> 
            $(id).innerHTML += "<p>#{x.toHtml()}</p>"
    ms = new MockSearch
    ms.search kw, (results) ->
        appender("gr", results.google)
        appender("tr", results.twitter)

You might notice that the function has an @ symbol prepended to it (a shortcut for this). When defined at the top level of a script, this becomes the global object. In the case of a script in a web page, the global object is the window object, which will allow it to be referenced in the web page you see in Listing 8.

The doSearch function does a lot in just a few lines of code. The code:

  • Defines a local function called $ that's basically a shortcut to the ever useful document.getElementById function. Use this to get the keyword entered in the search form in Listing 8.
  • Defines another local function called appender, which will take the ID of an element in the DOM and an array. It will then iterate over the array, create an HTML string, and append to the element with the given ID.
  • Creates a MockSearch object and invokes its search method.
  • Passes the keyword from the form and creates a callback function.

    The callback function uses appender to append the search results from Google to one div and the search results from Twitter in the other.

Now you can simply compile all of the code and deploy it. Figure 1 shows the web page with the mock data.


Figure 1. Search page with mock data
Search page with mock data

The example might not look impressive, but it demonstrates all of the functions that are needed on the client side. Though you don't have the server side coded yet, you can be fairly confident that the application will work as long as the server-side code produces data structured like the mock data.


Conclusion

In this article, I took CoffeeScript out of the laboratory and used it to start building something real. Combined with node.js, CoffeeScript gives you the opportunity to write a complete application, client and server both, using the same elegant programming language. You're well positioned to reuse some of the same code when building the server side of the application in the final part of this series. Stay tuned.



Download

DescriptionNameSizeDownload method
Article source codecs3.zip5KBHTTP

Information about download methods


Resources

Learn

Get products and technologies

Discuss

About the author

Michael Galpin's photo

Michael Galpin is a software engineer at Google. He is a co-author of the book Android in iPractice and a frequent contributor to developerWorks. For a sneak peek at what he's up to next, check out his blog or follow him on Twitter @michaelg or Google+ Michael Galpin.

Report abuse help

Report abuse

Thank you. This entry has been flagged for moderator attention.


Report abuse help

Report abuse

Report abuse submission failed. Please try again later.


developerWorks: Sign in


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Select information in your developerWorks profile is displayed to the public, but you may edit the information at any time. Your first name, last name (unless you choose to hide them), and display name will accompany the content that you post.

Choose your display name

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


Rate this article

Comments

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Web development
ArticleID=792636
ArticleTitle=Your first cup of CoffeeScript, Part 3: Using CoffeeScript on the client
publish-date=02142012

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

For articles in technology zones (such as Java technology, Linux, Open source, XML), Popular tags shows the top tags for all technology zones. For articles in product zones (such as Info Mgmt, Rational, WebSphere), Popular tags shows the top tags for just that product zone.

For articles in technology zones (such as Java technology, Linux, Open source, XML), My tags shows your tags for all technology zones. For articles in product zones (such as Info Mgmt, Rational, WebSphere), My tags shows your tags for just that product zone.

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Try IBM PureSystems. No charge.

Special offers