Monday, February 25, 2013

Quick Links - February 25 2013 Coffeescript and Web Essentials

Hey all a couple of interesting finds for the day:

The first link is to the change log for Coffeescript which is up to v 1.5.  I usually don't post about version changes but in this particular update they have added literate programming features, which I'm not overly familiar with but seems really cool.

The second is a link talking about Web Essentials 2012.2.  I took a Microsoft course over the weekend and it inspired me to drop that here.

Enjoy

Thursday, February 21, 2013

Coffeescript And Backbone.js - Convert Reminders App

Coffeescript And Backbone.js - Convert Reminders App

Hey all,

Gonna be a bit late on the post regarding callbacks in javascript.  Ran into a little time consuming issue while updating my gift list app and haven't had time to work promises into it yet.  That should be on it's way soon but as Space Hog would say "In the mean timeeeeee"... More Coffeescript, this time with some Backbone.js.

I've been meaing to change my Messages and Reminders app from vanilla javascript and jQuery to something in Coffeescript, Backbone.js and jQuery(w/UI).  Why you ask?  Well the app is essentially a single page web app already and though the initial version is working fine from the front-end perspective right now, some recent changes I wanted to add showed an increasing need for a bit more organization and robustness in the code so...

If you haven't seen Messages and Reminders, check it out, sign up, play around with it, a new version should be out before the end of the month.  So basically we have a web app that allows you to send messages back and forth between yourself and other members as well as add reminders to yourself or convert a message to a reminder.  Pretty simple stuff.  Lets take a look at some of the code:


class Message extends Backbone.Model 
  defaults: 
    to : "Me" 
    from : "You" 
    title : "Hey" 
    body : "What's up" 
    date : "02/18/2013"

Models are the basic building blocks of Backbone.js.  Here we are creating a Message class which will extend the base model class and then we add some defaults to that new class.  By extending the model class we get all kinds of great utility methods including a getter and setter for our properties and other great methods.  The defaults shown here are the default values of our model properties if we instantiate an instance and don't set the properties at that time.

If we do this


newMessage = new Message() 
newMessage.to ## 'To'

or if we do this


newMesage = new Message({to: 'You'})
newMessage.to ## 'You'


Ok, hope that is clear as mud.
Next we are going to setup a collection which will hold our models


class MailBox extends Backbone.Collection

Wow is that it for a collection? Yup. Actually for the purposes of this article we could even write

reminders = new Backbone.Collection()

So why extend if we could just instantiate a new instace of a collection. Mostly for future issues including adding some error checking on the collection.
Something I should mention just occured to me while discussing collections. Backbone has one hard dependency, either Underscore.js or lo-dash. Both do essentially the same thing, lo-dash is smaller and faster whereas Underscore is larger but maintains some support for older browsers. Either will work. The reason for my sudden memory flash of Undercore is that Backbone proxies 28 iteration functions to collections such as forEach, map, reduce, min, max and more. This makes collections super useful in any data heavy web app. I should note that collections are not the only reason Underscore is a requirement for Backbone so don't assume just because you are not planning on using the iteration functions you won't have to include Underscore.


Next up we get into some views


class MessageView extends Backbone.View 
  tagName: "li" 
  className: "message" 
   model: Message 
   temp: "
      <%=to%>
      <%=from%>
      <%=title%>
      <%=body%>
      <%=date%>
   " 
 initialize:() => 
   @render() 
 render: () => 
 if @temp? && @model? 
   messageTmp = _.template(@temp) 
   @$el.append(messageTmp(@model.attributes)) 
 return @


Views are what we use to display data in a Backbone app.  They can reflect a model, collection or just a be a static representation of whatever you want.  Here we have the view that is created when a new Message model is added to a MailBox collection.  A few things to note about the view.  I am using the tagName and className properties to describe what type of element I want created, so a list element with a class of message.  The temp property is actually a template string that we will compile down and use to display the model data.  Here we are using Underscore templates but we could use whatever templating we wanted.  Then we have the initialize function which is our constructor, this function is called when you create a new instance of your model so whatever setup needs to be done do it here.  In this case I am simply calling into the render function.  The render function's default implementation is a no-op, it's provided to be overridden to contain whatever needs to be done to get your view properly rendered.  So in this render we compile our template down and send in @model.attributes which is a property provided that cotains the model data as a hash or in this case {to:"To", from: "From", title: "Title"..etc}.  We then append the string to the views @$el which is a wrapper function that uses jQuery or Zepto if they are available on @el which is the current element.  We then return @ (javascripts this) which is a common practice to allow method chaining.  Why did we call render from initalize, just cause.  It basically lets me simplify the calling code from new MessageView({model:model}).render() to new MessageView({model:model}).


class MailBoxView extends Backbone.View 
  tagName : "ul" 
  className : "mail-box" 
  initialize:() => 
    @listenTo(@collection, "add", @render) 
  render: () => 
    if @collection? && @collection.length 
      newMessage = @collection.at(@collection.length - 1) 
      @$el.append(new MessageView(model:newMessage).el) 
    return @

This is the code for the MailBox collection view.  Notice in the initialize function(or constructor) we call @listenTo(@collection, "add", @render).  listenTo is from Backbone events.  It takes a collection or model, an event type and a function.  When the listening event type is fired by the collection or model the callback function executes.  So here, when a model is added to the views collection, we execute the render function of the view.  So where does this collection come from? Look further down the code to the MailBoxView instansiation reminderView = new MailBoxView(collection: reminders).  We add the collection reminders here to the new MailBoxView.  Why not add the collection as a property?  De-coupling.  We don't want this particular collection tied to the view in that way, we want the backbone events to do what they are there for which at least in part is helping our different application pieces communicate.  There is way more on events in the Backbone documentation, you can even create and use custom events which can be extremely useful.


class CreateMessageView extends Backbone.View 
  events: "click .submit": "addMessage" 
  addMessage: () => 
    to = @$el.find(".to").val() 
    from = @$el.find(".from").val() 
    title = @$el.find(".title").val() 
    body = @$el.find(".body").val() 
    date = @$el.find(".date").val() 
  newMessage = new Message( 
    to: to from: 
    from title: 
    title body: 
    body 
    date: date 
  ) 
  @collection.add(newMessage) 
  @render() 
  return 
 render: () => 
   @$el.find("input:not(button)").val("") 
   return @ 
 initialize: () =>

Alright! More events!  Here we are adding the events using the events property on the view.  This is a form of event delegation which you may also be familar with from jQuery, which would look like $("#createMessage").on("click", ".submit", @addMessage).  Event delegation speeds up events by having the event bubble only as far as the containing element.  A problem with delegation in Backbone is that if the object is destroyed without properly removing the event binding first, you can create a memory leak[citation needed].  So keep that in mind.  Now back to what's going on here.  On clicking the submit button we call addMessage which get's the values of the input fields and creates a new message (newMessage) of the type Message with the field values.  We then add the new model to the collection, which remeber will cause the MailBox view to render the new Message in it's ul element because it is listening for changes in this collection.  So where is the "#createMessage" element from?  Well we bind that directly to an existing DOM element that was rendered when the page was created

createView = new CreateMessageView( 
 collection: reminders 
 el: document.getElementById("createMessage") 
 )

Notice again the collection being set to reminders and here we see that el is explicitly bound to the DOM element instead of creating an element to insert data into.


reminderView = new MailBoxView( 
 collection: reminders 
 ) 
$("#reminder").append(reminderView.el)

The final line ties it together by creating the reminder view and attaching it to the DOM at the "#reminder" element.

You can see the code here

That was a bit long for the type of overview I wanted to do but I think I covered the basics.  Next time I talk at length about Coffeescript I'm hoping to do some routing and show some use of Backbone.sync.

Wednesday, February 13, 2013

Quick Links - February 13 2013

A few more quicklinks for the day:

The first two are Coffeescript related, first is another Coffeescript book, this one has interactive features and the second is a cheat sheet reference for Coffeescript.

The second is under the javascript heading but could also apply to Coffeescript, it's a discussion on context binding, which if you've done any amount of front-end work you've had issues with, which are discussed here.

Tuesday, February 12, 2013

Quick Links - February 12 2013

A couple of free on-line Coffeescript books:

The first has a new updated paid version available but it's still very usefull as a simple introduction or quick reference.  The second is longer and more in depth from a conceptual perspective.  Both worth a read.

Monday, February 11, 2013

Quick Links - February 11 2013

A couple of good reads:

The first is more info about source maps as dicsussed in my earlier post.  The second is a good write up on how to write optimized javascript.

Along the lines of javascript and more specifically node.js, I"m hoping to have a post up later in the week about promises in node and how they can help get you out of call back hell.

Friday, February 8, 2013

Quick Links - February 8 2013

Just a couple of good reads I found today:

Both are related to the pub/sub observer pattern found often in event implemenations.  Anyone who's had to implement their own pub/sub system knows it comes with some issues, which both discuss and search for answers to.

Wednesday, February 6, 2013

Oh yeah, Coffeescript (Redux)

List Comprehensions

In my previous post on Coffeescript I stated that during my initial impression I noted that there were some "structural changes" to the ways loops were formatted.  That's not really the best way to state it.  In Coffeescript most loops are actually List Comprehesions.

List comprehensions are based on the mathmatical set builder notation, check the Wikipedia article for the specifics but the basics are

result = (func x for x in [0..20] where x%2 == 0)

That basically breaks down to give me the result of calling func x on the set, x is 0 to 20 where x mod 2 is even.  Seemed a bit complicated to me at first but it's really quite a powerful tool.

First all loops are based on this so a simple loop from 0 to x is


for i in [0..x]

Pretty simple, it also helps clear up the forEach on objects or lack there of in current javascript

output = ""

obj = 
 prop1: "hello ", 
 prop2: "world"

for i, prop of obj 
 output += prop 

console.log(output) ## hello world

Note here the use of the "of" keyword this is used to signal that we are iterating over an object and not an array.  You can also avoid any properties that may be inherited from the prototype by added the "own" keyword


obj = 
 prop1: "hello ", 
 prop2: "world"

for own i, prop of obj
 output += prop 

console.log(output) ## hello world


Here's an excellent example of the usefulness of list comprehensions:

square = (x) -> x * x 
results = (square x for x in [0..20] when x%2 == 0) 
console.log(results) ##[0, 4, 16, 36, 64, 100, 144, 196, 256, 324, 400]

Wasn't that super useful!  Ok, not so much, but what you should take away is that this basically gives you native forEach(as stated earlier), map, filter/select functionality which is really convenient when dealing with data or even the DOM.

Source Maps

In my first post about Coffeescript I mentioned that when I first approached the language the fact that it compiled down to javascript that would have to be debugged was a big drawback in my eyes.  The thought being that having to determine what javascript was associated with what Coffeescript was simply an annoying extra step in debugging.  This isn't really the case in practice and now not an issue at all because of Source Maps.

Source Maps are available in Chrome, hopefully Firefox soon and someday Internet Explorer.  They are not a feature specifically of Coffeescript.  The idea is that a source map is used to map output javascript back to the compiled language in this case Coffeescript.  So opening your dev tools you would be able to see the original Coffeescript, set breakpoints and have errors that would point back to the line in the original Coffeescript.  Pretty cool eh.  As I said this isn't a feature of the Coffeescript language but the browser or other dev tools.  JQuery as of v.1.9 have source maps available from the minified version back to development version.  Source maps for the main Coffeescript project are currently kind of up in the air but... Coffeescript Redux a re-write of the original compiler which aims to maintain the language structure but add some optimizations, have added support for source maps to Coffeescript.

Source maps can help remove a layer of complexity some people may see with Coffeescript development.  For more on source maps check it here.

Update: Source maps are now available in Coffeescript, please see this post for more information.