The Refresh Test

Apr 10 2014

How many times has the following happened to you?

You go to a web site and it asks you to create an account. You fill out a form with all the obvious fields and hit submit. The page refreshes and shows you the form again.

Phone Number is required

Well, that’s annoying. There was no indication that the site needed your phone number. You prefer not to give out your phone number to every web site, but this one is run by a company you trust, so you scroll down and fill it out. You submit the form again.

Password is required

What the heck!? You already entered a password! You scroll down to the form and see that the fields are now empty. It turns out that even though you filled out the password fields the first time, after you missed the phone number they were cleared. You fill them out and submit the form again.

Username is not available

At this point you’re ready to throw your computer out the window. There are fewer things more frustrating than trying to get your data into the exact shape a web site wants, especially if it clears fields every time you fail.

Another annoyance: just about every time I order something online, right after I input my credit card information, I am presented with a spinner animation and the text “Do not hit the back button or refresh your browser!” It’s terrifying that a company that is taking my money over the Internet can’t handle me refreshing the page without charging my card twice.

The sad thing is that both of these problems are totally solvable. In fact, they’ve been easy to solve for over a decade. Yet you still see them all the time.

Lessons from Live Reloading

Recently I spent some time playing with Ember App Kit. Ember App Kit is a suggested project structure for your applications built by Stefan Penner (and a bunch of other awesome developers). It’s really great and if you’ve never tried it out you should![1]

One feature Ember App Kit includes out of the box is support for connect-livereload, which automatically reloads your changes in your browser whenever you save a file.

It sounds like a minor thing, but after using it for a few hours having to manually hit Cmd-R feels like a chore. It’s a great little productivity booster.

Live Reload also has a side effect: it encourages you to make your application refresh resistant.

In my application I had a multi-step wizard where you had to enter many form fields at once, and I found it so frustrating to have all my form data pulled out from underneath me every time I hit save.

The frustration led me to persist the form data temporarily in localStorage. Once I did that, every time my application refreshed it looked exactly the same as it did before. It was probably a grand total of 10 minutes of work, and my application was much more resilient for it.

The Refresh Test

A great experiment to perform on a Javascript heavy application is to simply refresh the page and see where you end up. Does it look the same as before? Did you lose any work?

Users will put up with losing a small amount of state on refresh, for example if they’d expanded a menu and it’s suddenly collapsed, but you should never throw away what they were working on.

One thing I love about Ember.js is that its router makes you think in terms of URLs, which gives you a great head start for handling refreshes and the dreaded back button.

Many people think of URLs as files, because in the past requesting a path like profile.php?id=eviltrout meant you really wanted a file on the server called profile.php with the parameter eviltrout.

I find it’s better to think of a URL as the serialized state of your application. A path of /profiles/eviltrout should mean “I’m viewing eviltrout’s profile.”

If you’re building a Javascript application and the URL is not changing as your users navigate around, that is practically begging to give them a bad experience at some point. Not only can they be easily frustrated if they hit the back or refresh buttons, but they won’t be able to bookmark or share links with others.

I’m not suggesting that the URL contain every possible interaction a user can make; if you do that you will end up with a huge headache and a meaningless URL. Instead, you should focus on the most important things a user will want to see when the page is refreshed. For example, on Discourse we maintain a user’s scroll position in a topic by changing the URL as they scroll.

Going forward, I’m going to make sure that all my applications handle refreshing elegantly and I recommend you do too! If you’re interested in more on this topic, Tom Dale has a great talk on this called Stop Breaking the Web.


1. If you’re a fan of using bleeding edge stuff, check out Stefan Penner’s ember-cli and Jo Liss' broccoli. Ember App Kit works well today but those projects are a glimpse of the future of where Ember development is headed.

I'm in New York City offering Ember.js training with Erik Bryn on May 22 & 23. Learn more!
View the full article to comment on it

Embedding Discourse in Static Sites

Jan 22 2014

It’s been possible to embed comments from a Discourse forum on to other sites for a while now, but the only publishing software we supported was Wordpress.

Many people, myself included, don’t use Wordpress to run their sites. This very blog is a series of static HTML documents that are generated by Middleman. (Like Discourse itself, my blog is open source; you can find the code here so feel free to submit pull requests!).

Well… Good News Everyone! It’s now possible to embed Discourse content into any HTML document. In fact, as you can see below, the comments on this very site are now handled by a Discourse instance I set up.

How it Works

You can now configure Discourse to support embedding. Once you’ve done that, you paste a small snippet of Javascript into your site template and you’re off to the races.

Discourse will create topics for your blog entries if you provide it with an RSS or Atom feed. It’s also smart enough to update them if the content changes, say for corrections or typos. When any users of your forum post comments, they will automatically be inserted into your blog.

If your site does not have an XML feed, Discourse will create topics based on your page contents using a readability algorithm. It’s remarkably accurate for those cases when your site doesn’t have a feed.

How to Set up Embedding

  1. Install a Discourse Forum. We currently recommend using discourse_docker to do this. If you have ruby on your computer, you can even do it via a command line wizard.

  2. Navigate to the Embedding Site Settings. The URL will be something like:

    http://discourse.yourdomain.com/admin/site_settings/category/embedding

  3. Configure the settings appropriately. Here’s how it looks for my blog:

    Embedding Settings

  4. In your blog template, paste in the following snippet of Javascript and a <div> tag for where you’d like the comments to appear:

    <div id="discourse-comments"></div>
    
    <script type="text/javascript">
      var discourseUrl = "http://fishtank.eviltrout.com/",
          discourseEmbedUrl = 'http://eviltrout.com/link-to-blog-entry.html';
    
      (function() {
        var d = document.createElement('script'); d.type = 'text/javascript'; d.async = true;
          d.src = discourseUrl + 'javascripts/embed.js';
        (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(d);
      })();
    </script>
    

    Configuration

    1. You will have to change the discourseUrl variable so it points to the root URL of your Discourse forum.
    2. Make sure discourseEmbedUrl is the canonical URL to the page where you are embedding Discourse. You will want to make sure this uniquely identifies the page. For my blog template, I use the following code to link to the article: discourseEmbedUrl = 'http://eviltrout.com<%= current_page.url %>'

  5. Reload your blog. Your blog posts should start syncing over to your forum and any comments should be imported into your blog. It’s that easy!

Going Forward

eviltrout.com has been running this set up for a few weeks now and it’s been great! Of course, like with any new feature of Discourse we’d love to hear your feedback so we can iterate on it and make it better. Let us know how it works for your use case.

I'm in New York City offering Ember.js training with Erik Bryn on May 22 & 23. Learn more!
View the full article to comment on it

Hiding Offscreen Content in Ember.js

Jan 4 2014

Everything you render in a browser, whether it’s a blog post or a tweet or a video, has a performance cost.

At the very least, you will be asking the browser to render a handful of tags and text elements that make up your user interface. That structure, a subtree in the browser’s DOM, can be quite complicated and memory intensive.

The more tags and elements you render, the slower the browser is going to perform, and the more memory it is going to use to do it. It follows that if you give the browser less work to do, it will do it faster.

This principle holds true even if you are using a browser application framework like Ember.js. Every data binding you make between an element and an object has a cost. If you reduce your bindings and views, your interface will feel snappier.

Long Lived Applications

Discourse makes heavy use of infinite scrolling. If a user is reading a long topic with many posts, new posts will stream in asynchronously from the server as the scroll position approaches the end of the browser’s viewport.

For shorter topics, adding all that extra content to the DOM was not a performance issue. Modern browsers, even on mobile devices, could handle rendering of hundreds of posts of formatted text without breaking a sweat.

However, as Discourse installs began to see heavy use, we found some topics had thousands of posts, and some users would read many of them in one sitting. All of those inserted posts started having a negative effect; browsers would often start to feel “choppy” and could even crash, leaving users frustrated.

Cloaking Offscreen Content

The obvious solution to this problem was to unload content from the DOM as it scrolled offscreen and render it again if it came back onscreen.

The issue with this is that if you remove an element from the DOM, the browser will reflow, and all the other content underneath it will jump back upwards. In order to prevent the browser viewport from moving, you have to replace the element with a simpler one that has the exact same height as the element it’s replacing.

One of Ember’s strengths is how it breaks down your UI into a hierarchy of views. You have your ApplicationView which contains your TopicView and a collection of PostViews and so forth.

I took advantage of this structure and implemented a CloakedView class.

The idea is any of your views can be contained in a cloak. When onscreen, the cloak renders the contained view. When offscreen, the cloak will copy the height of its rendered content and unload it.

A PostView doesn’t care if it’s cloaked or not. It should only be concerned with how to render a post. We can choose to cloak when we display a list of posts with a special helper. So instead of rendering a collection of Posts like so:

{{collection content=topic.posts itemViewClass="Discourse.PostView"}}

We can drop in a replacement like so:

{{cloaked-collection content=topic.posts cloakView="post"}}

ember-cloaking

After implementing cloaking, there was an immediate drop of 30% RAM usage in long Discourse topics. Scrolling also remains smooth even if many posts are browser in one sitting. We’ve been running it in production for about a month and it’s been a huge win!

I’ve extracted the cloaking logic into a library called ember-cloaking.

For now it only works with vertical scrolling, but if you are doing a large amount of horizontal scrolling I’m sure it could be adjusted to work without too much effort.

The fact that I was able to implement this functionality in a generic way without much code is a testament to Ember’s excellent design.

If your application is rendering many items in the browser at once, especially if you are implementing infinite scrolling, you should give it a shot and let me know how it works for you!

I'm in New York City offering Ember.js training with Erik Bryn on May 22 & 23. Learn more!
View the full article to comment on it

Internationalization Support in Ember.js

Nov 24 2013

One thing I’m really proud of is that when we launched Discourse, we had first class Internationalization (i18n) support ready to be used. Our first release only English, but thanks to our community we have 18 localizations of our software in progress! Here’s what Discourse looks like in Simplified Chinese:

Discourse in Chinese

On the server side, Discourse uses Rails' built in i18n support. It has been around for a long time and works easily so I won’t go into that. Check out the documentation for your server side framework of choice for more.

I18n in Ember.js

Our client side application is written in Ember.js, which doesn’t have built in support for i18n. However, it’s not difficult to add it in.

We use i18n-js, a project whose goal is to bring Rails translation support to Javascript. Don’t worry if you don’t use Rails on the server side. You can use all of the code in this post outside of Rails if you like. The Javascript code in 1i8n-js is all you’ll need.

Once you’ve included i18n-js in your project, you will have access to an I18n object in your javascript code to perform translations with. The first thing you’ll need to do is include a translations.js file that includes all your translations. Here’s how a simple one could look:

I18n.translations = {
  en: {
    hello: 'hello',
    cookieCount: {
      one: 'You have {{count}} cookie.',
      other: 'You have {{count}} cookies. Yum!'
    }
  },

  fr: {
    hello: 'bonjour'
    cookieCount: {
      one: 'Vous avez {{count}} biscuit.',
      other: 'Vous avez {{count}} biscuits. Le Yum!'
    }
  }
};

And then if you wanted to output a translation you can use the i18n.t function:

console.log(I18n.t('hello'));   // outputs hello because the default locale is `en`

I18n.locale = 'fr';
console.log(I18n.t('hello'));   // outputs bonjour

In an Ember app though, you’ll want to be able to access those translations in your handlebars templates. To do this, you’ll need to define a helper. You can just copy and paste this code into your app:

Ember.Handlebars.registerHelper('i18n', function(property, options) {
  var params = options.hash,
      self = this;

  // Support variable interpolation for our string
  Object.keys(params).forEach(function (key) {
    params[key] = Em.Handlebars.get(self, params[key], options);
  });

  return I18n.t(property, params);
});

Now your templates are ready to be translated:

<h1>{{i18n hello}}</h1>

<p>{{i18n cookieCount count=user.cookies.length}}</p>

Note that the I18n library is smart enough to notice when you supply a parameter named count to select the correct pluralization for a key. If the user has one cookie it won’t add that pesky “s.”

I18n support is so easy to add that I recommend it for just about every web project unless you’re absolutely sure you’ll never need it in another language. The Internet is a lot bigger than your home country, go forth and make it easier to translate!

I'm in New York City offering Ember.js training with Erik Bryn on May 22 & 23. Learn more!
View the full article to comment on it

Enemy of the State

Oct 5 2013

I learned very quickly while working on a large open source project is that it is important to make my code hard to break. The primary line of defense for this is a comprehensive test suite, but I think it’s also very important to create functions that are easy to use and difficult to damage.

I find I even code this way on personal projects that will never be released. Even if you never work on a team with other developers, there is a good chance you will forget a lot of implementation details of the code that you aren’t actively working on. You need to protect your code from yourself!

I think a lot about state these days. How much data should an object have, and how should it expose that to other objects? I find many bugs are related to the state and scope of data not being what you’d expect.

An Example: ActiveRecord

ActiveRecord makes it easy to retrieve all rows from database and represent them as objects:

Product.all.each do |p|
  puts p.name
end

We didn’t have to specify that we wanted the name column from the database before we outputted it; by default ActiveRecord includes all the columns in the table.

Over time, many frequently used tables in databases such as Product tend to get more columns added to them to support new features. You might find that your table that started off with 4 columns is eventually over 50!

There is overhead involved in returning all those extra columns from the database. At the very least, the database has to send more data across the wire to your application. On top of that, Rails has to deserialize all the columns into their appropriate types in the object.

When returning a single Product you will probably not notice much of a difference. However, when returning hundreds of rows at once, the overhead can add up quite a bit.

Selecting only what you need

ActiveRecord provides a method called select that can be used choose the columns returned from the database. We could write something like this:

Product.select([:id, :name]).each do |p|
  puts p.name
end

This will certainly execute faster than the Products.all query above. However, if you do this, you are exposing yourself to many bugs due to inconsistent state.

The danger here is ActiveRecord returns a mixed state instance of Product. The returned object looks like a Product. It has all of the instance methods you defined on Product, however, it is missing some of the data that is normally there.

To illustrate this, imagine you have a function that returns a product’s name, but adds an asterisk if it’s on sale:

def fancy_product_title(product)
  if product.on_sale?
    return product.name + "*"
  else
    return product.name
  end
end

In this case, our method checks the on_sale column in the database to determine whether to append the asterisk. However, if you retrieved the Product using select([:id, :name]) you would not have this column present, and even if the product was on sale your users wouldn’t know about it.

Now this might seem like a pretty easy bug to squash. Any competant programmer could adjust this code to return on_sale in the select clause if if they saw it wasn’t ever being displayed.

That is demanding a much broader knowledge of the application and the flow of data than is necessary. It takes more development time, and doesn’t scale well when your codebase grows. Also, who wants to constantly think “hey, do I have all the data I need in this object to do my work?”

Keep it Consistent

You can eliminate any entire class of bugs by never using select. You should insist that your object instances always include all their data members.

What about the performance issues? I suggest instead that you design your data structures in a different way. Rather than returning inconsistent Product models, why not create a method that returns BasicProduct objects?

All Product instances have enough data to transform into BasicProduct instances if they need to. If you like inheritance you could make a Product extend a BasicProduct. If you’re not a fan of inheritance you could create a to_basic method.

This is just one example of how easy it is to leave things in an inconsistent state, especially when considering performance. I suggest that you make an effort to keep your data in sync as much as possible, even if it involves a little data modelling. You’ll have fewer bugs, and your code will be better to use in the long run.

I'm in New York City offering Ember.js training with Erik Bryn on May 22 & 23. Learn more!
View the full article to comment on it

Let's Talk about Browser Applications (and Forums and Discourse)

Jul 31 2013

Back in February, I gave a presentation on Discourse and client side MVC at TechTalksTO.

It wasn’t recorded, but I’ve taken the liberty of creating a video version of the presentation with an audio track.

While the presentation is about Browser Applications, I take a large detour in the beginning to talk about Discourse and Forum software in general. Enjoy!

I'm in New York City offering Ember.js training with Erik Bryn on May 22 & 23. Learn more!
View the full article to comment on it

Computed Property Macros

Jul 7 2013

Computed Properties

By design, Handlebars templates don’t allow complex expressions. You are given an {{#if}} block helper, but it can only evaluate whether something is “truthy” (aka true, a non-empty string or array or other value that is not undefined or null.)

For example, you can’t do something like this:

{{#if (eyes.length == 1) && (horns.length == 1) && flies && (color == 'purple') && eatsDudes}}
  <i>It was a one-eyed, one-horned, flying purple people eater!</i>
{{/if}}

Handlebars encourages you to use a single evaluation for your logic:

{{#if purplePeopleEater}}
  <i>It was a one-eyed, one-horned, flying purple people eater!</i>
{{/if}}

I think the second example is much clearer and easier to follow. Even though some other templating languages might allow you to use more complex expressions in your templates like the first example, I’d recommend aggregating them anyway. It will make your life a lot easier.

Ember gives you a great tool out of the box to do this easily called computed properties. I’ve written about them before, but in a nutshell they allow you to create a function that transforms one or more properties into another single property. In this case, you could make one like this:

App.Creature = Ember.Object.extend({

  purplePeopleEater: function() {
    return (this.get('eyes.length') === 1) &&
           (this.get('horns.length') === 1) &&
           (this.get('flies') &&
           (this.get('color') === 'purple') &&
           (this.get('eatsDudes')));
  }.property('eyes.length', 'horns.length', 'flies', 'color', 'eatsDudes')

});

By adding .property() to your function prototype, this tells Ember that it’s a computed property. The 5 arguments tell Ember to cache the result unless any of those properties change. As long as our Creature’s values don’t change, the result won’t be recalculated.

Computed Property Macros

Computed Properties are an important feature in Ember and are understood well developers. However, there is a less well known way to declare computed properties that is often a lot easier and clearer: using the Ember.computed set of functions. They are shortcuts for creating common types of computed properties. Here’s some examples:

App.Creature = Ember.Object.extend({
  eyesBlue: Ember.computed.equal('eyes', 'blue'),

  hasTwoBananas: Ember.computed.gte('bananas.length', 2),

  sick: Ember.computed.not('healthy'),

  radical: Ember.computed.and('ninja', 'turtle'),

  staff: Ember.computed.or('moderator', 'admin')
});

You can find a full list of macros on the Ember API site.

Not only are the computed property macros often shorter to write, but you don’t have to specify the dependant properties for caching like you do when using the .property() method, so I find them to be less error prone. Here’s how I might re-write the purplePeopleEater property by breaking it into smaller macros:

App.Creature = Ember.Object.extend({
  oneEyed: Ember.computed.equal('eyes.length', 1),
  oneHorned: Ember.computed.equal('horns.length', 1),
  purple: Ember.computed.equal('color', 'purple'),

  purplePeopleEater: Ember.computed.and('oneEyed', 'oneHorned', 'flies', 'purple', 'eatsDudes')
});

It’s a lot more DRY than the previous solution. In the first solution we had to write every property name twice, now we only write it once.

A secondary benefit of this approach is we’ve cached the internal properties such as oneEyed. If another computed property needed that comparison, we already have it available and cached.

Once you start to use these macros you won’t stop! You’ll find yourself breaking long sequences of conditionals into smaller boolean chunks that are easier to re-use and cache for performance. Have fun!

I'm in New York City offering Ember.js training with Erik Bryn on May 22 & 23. Learn more!
View the full article to comment on it

Adding Support for Search Engines to your Javascript Applications

Jun 19 2013

It’s a myth that if you use a client side MVC framework that your application’s content cannot be indexed by search engines. In fact, Discourse forums were indexable by Google the day we launched.

Search engine visibility does, however, require a little more work to implement. This is a real trade off you’ll have to consider before you decide to go with an MVC framework instead of an application that does its rendering on the server side.

Before you get scared off: I’d like to point out that our search engine code was done by Sam Saffron in a day! This extra work might take you less time than you thought.

Getting Started: Pretty URLs

Out of the box, most client side MVC frameworks will default to hash-based URLs that take advantage of the fact that characters in a URL after an # are not passed through to the server. Once the Javascript application boots up it looks at hash data and figures out what it has to do.

Modern browsers have a better alternative to hash-based URLs: The HTML5 History API. The History API allows your Javascript code to modify the URL without reloading the entire page. Instead of URLs like http://yoursite.com/#/users/eviltrout you can support http://yoursite.com/users/eviltrout.

There are two downsides to using the History API. The first is Internet Explorer only started supporting it IE10. If you have to support IE9, you’ll want to stick with hashes. (Note: Discourse actually works on IE9, but the URL does not update as the user goes around. We’ve accepted this trade off.)

The second downside is that you have to modify your server to serve up your Javascript application regardless of what URL is requested. You need to do this because if you change the browser URL and the user refreshes their browser the server will look for a document at that path that doesn’t exist.

Serving Content

The second downside I mentioned actually has an nice upside to it. Even if you are serving up the same Javascript code regardless of URL, there is still an opportunity for the server to do some custom work.

The trick is to serve up two things in one document: your Javascript application and the basic markup for search engines in a <noscript> tag. If you’re unfamiliar with a the <noscript> tag, it’s designed for rendering versions of a resource to a clients like search engines that don’t support Javascript.

This is really easy to do in Ruby on Rails (and probably other frameworks that I’m less familiar with!). Your application.html.erb can look like this:

<html>
  <body>
    <section id='main'></section>
    <noscript>
      <%= yield %>
    </noscript>
  </body>
  ... load your Javascript code here into #main
</html>

With this approach, if any server side route renders a simple HTML document, it will end up in the <noscript> tag for indexing. I wouldn’t spend much time on what the HTML looks like. It’s meant to be read by a robot! Just use very basic HTML. To preview what a search engine will see, you can turn off Javascript support in your browser and hit refresh.

We’ve found it advantageous to use the same URLs for our JSON API as for our routes in the Javascript application. If a URL is requested via XHR or otherwise specifies the JSON content type, it will receive JSON back.

In Rails, you can reuse the same logic for finding your objects, and then choose the JSON or HTML rendering path in the end. Here’s a simplified version of our user#show route:

def show
  @user = fetch_user_from_params

  respond_to do |format|
    format.html do
      # doing nothing here renders show.html.erb with the basic user HTML in <noscript>
    end

    format.json do
      render_json_dump(UserSerializer.new(@user))
    end
  end
end

Note that you don’t have to implement HTML views for all your routes, just the ones that you want to index. The others will just render nothing into <noscript>.

One More Thing

If you get an HTML request for a URL that also responds with JSON, there is a good chance your application is going to make a call to the same API endpoint after it loads to retrieve the data in JSON so it can be rendered.

You can avoid this unnecessary round trip by rendering the JSON result into a variable in a <script> tag. Then, when your Javascript application looks for your JSON, have it check to see if it exists in the document already. If it’s there, use it instead of making the extra request.

This approach is much faster for initial loads! If you’re interested in how it’s implemented in Discourse, check out:

I'm in New York City offering Ember.js training with Erik Bryn on May 22 & 23. Learn more!
View the full article to comment on it

AngularJS vs Ember

Jun 15 2013

Recently I got together with some local developers to discuss client side MVC frameworks. We ended up discussing many of the differences between AngularJS and Ember.

Discourse is an Ember application and has been since the first prototype, so I have a lot of experience with it. However, it became clear during the conversation with my peers that there was a lot about AngularJS I didn’t know.

There is evidence that AngularJS is beating out Ember in terms of developer mind share: there are more Stack Overflow questions dedicated to AngularJS. AngularJS has more stars and forks on Github. At a recent Javascript meetup in Toronto, when polled virtually every developer expressed interest in learning more about AngularJS. Clearly there is something to this framework!

I decided to take some time to seriously investigate AngularJS and see what all the fuss was about. I read through as much documentation, blog posts and guides as I could. I downloaded AngularJS and made simple applications. I reached out to local developers and pestered them with questions about the framework.

I have a good idea now why AngularJS is gaining momentum: it is simpler. There is a lot less to the framework and as a consequence it’s easier to learn. If I were to rank the amount of tools various client side MVC frameworks give you, Angular seems to exist somewhere near the half way point between Backbone and Ember.

The pitfalls of simplicity

A few years ago, many Rails developers I knew were excited about Sinatra. Sinatra is far simpler than Rails. It allocates a fraction of the objects Rails does. I observed a pattern as those developers started to build out their applications. Some were used to Rails' large toolbox of convenience functions so they included ActiveSupport. Some needed ORMs so they included ActiveRecord. At that point, what was the advantage of Sinatra? You were basically running a Rails application.

Framework simplicity is good if your application is meant to be simple. But you should be cautious when choosing simplicity if your application is ambitious and you care about supporting it for a long time.

Don’t get me wrong: if an API is convoluted and verbose, and a competing one is equally functional yet simpler to use, by all means use the competitor. However, people are far too quick to mistake simplicity for good design.

Ember has more concepts to learn and more to wrap your head around than AngularJS. Before you write off Ember due to its complexity, consider why the developers added all that extra stuff. Perhaps it’s there for a reason?

Ember is a toolbox full of concepts you will find useful if you want to build a large and maintainable application. The trade offs it has made in its API are there to help you structure your code in a sane way. As you learn Ember you will notice several philosophies and opinions that are completely absent from the AngularJS framework.

This is far better illustrated via example. In this post, I’m going to try and demonstrate a few major shortcomings in AngularJS and how the Ember approach is much better.

In pursuit of a single source of truth

Let’s say you’re working on a web application that does rendering on the server. The current page you’re working on is meant to display a list of items as rows, and if the user clicks on a row, it will change color to indicate it’s been selected.

If you were using jQuery to do this, you’d likely bind a function to the click event on each row. When fired, your function would change the CSS class of the row to highlight it.

You can’t stop there, though. Your function also has to remove the CSS class from any other rows that were previously selected. That’s a little crazy if you think about it! Changing which item is selected means we have to know everywhere that it’s been represented in our UI.

Whenever you store the same piece of data in multiple places, it is likely to go out of sync. Additionally, your code ends up being longer and more complex as it has to manage all the various updates every time it changes.

Client side MVC (Model View Controller) frameworks like Ember and AngularJS separate your data model from its presentation. Your model becomes the single source of truth. If you change it, your HTML template changes automatically. If you want to know its current value, you read it from the model instead of the DOM.

This is a a huge boon to developer productivity while simultaneously reducing the potential for errors related to out of sync data.

What’s an AngularJS Model?

AngularJS touts itself as a MVC or MVW (Model View Whatever) framework.

It’s clear where AngularJS' view layer is: you annotate regular HTML documents with ng-* attributes and handlebars style {{variable}} expressions. It’s also easy to understand where the controllers are; you link Javascript classes to elements using ng-controller attributes.

What isn’t clear, especially if you come from a server side MVC background, is what is an AngularJS model? There is no standard Model base class, nor is there a component or interface in AngularJS that defines what a model is supposed to be.

In an AngularJS controller, you are given an object called $scope. Any data you attach to it is rendered in your HTML template:

function SomeCtrl($scope) {
  $scope.countries = ['can', 'usa', 'fra', 'jap'];
  $scope.user = {name: "Evil Trout"};
  $scope.age = 34;

  // Our template now can render {{age}}, {{user.name}} and a list of countries!
}

According to the AngularJS documentation any named data in an AngularJS $scope is a model, not just Javascript objects and arrays, but primitives, too! In the above snippet, there are three models!

What’s wrong with Javascript primitives as models?

AngularJS gives you tools you need to manage a single source of truth in your templates. This is a concept known as data binding. If we created a template that has an AngularJS expression {{age}}, we can say it’s bound to the $scope.age model. If you wrote {{age}} several times in one template, and executed $scope.age = 40 in your controller, all would update simultaneously.

There is a secondary level of data binding, however, that you need if you truly want to express a single source of truth, and that is within your data model itself. In other words, AngularJS stops short by only allowing for data binding only between your $scope and template, not within the structures in your Javascript code.

In Ember, all models extend the Ember.Object base class. When you do this, you gain the ability to declare relationships within and between models. For example:

App.Room = Ember.Object.extend({
  area: function() {
    return this.get('width') * this.get('height');
  }.property('width', 'height')
});

Here, we’ve created a model called Room. We’ve declared area which is known as a computed property. The property syntax you see at the end there tells Ember that the Room’s area depends on its width and height.

Creating an instance of this model is easy:

var room = App.Room.create({width: 10, height: 5});

Now we can create a template:

<p>Room:</p>

<p>{{width}} ft.</p>
<p>{{height}} ft.</p>
<p>{{area}} sq ft.</p>

And Ember would render the attributes correctly. In this case, it’s impossible for area to be out of sync with width and height. If either of those two properties change, area will be updated automatically.

Modeling this in AngularJS

Because AngularJS models are regular Javascript objects, AngularJS doesn’t have an equivalent to computed properties. However, you can approximate them using functions on your objects:

var Room = function(args) {
  this.width = args.width;
  this.height = args.height;
}

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

To access the area of our Room, you have to add a set of parentheses to your area() call:

<p>Room:</p>

<p>{{width}} ft.</p>
<p>{{height}} ft.</p>
<p>{{area()}} sq ft.</p>

This illustrates a key difference between Ember and AngularJS. Ember subscribes to the Uniform Access Principle. In an Ember template, regardless of whether you are accessing something that is computed or something that is a primitive, the expression looks the same. In AngularJS, functions have to be specifically demarcated.

This can cause maintainability nightmares down the road. Over time, in a large software project, you will inevitably want to replace something that was previously a primitive with a method. In Ember you can do this painlessly; in AngularJS you’ll have to update every template where that model is used.

Using getters and setters

It’s worth discussing a related trade-off you might have noticed in the Ember code above: to access properties of a model, you have to use getters and setters. This means a little extra typing, but you reap the same benefit in the Javascript code that you do in the template: replacing a primitive with a function will just work!

A secondary benefit to using getters and setters is you can chain them safely. Consider the following code:

console.log(room.inhabitant.name);

What happens if the inhabitant is not present? You’ll raise a Javascript error. In the Ember equivalent you’ll get undefined back, which makes it easier to write more resilient code:

// outputs undefined
console.log(room.get('inhabitant.name'));

Performance issues

There is another downside to using a functions instead of computed properties: it’s much slower.

In our Ember code, we expressed that area depends on width and height. In AngularJS, we didn’t do that. So how could AngularJS possibly know to re-render the area if the width or height changed? In fact, how does AngularJS ever know to re-render when things change if it’s not using special Javascript objects for models?

The answer is: it doesn’t. AngularJS uses a process called dirty checking to determine what it needs to update in the DOM. When a controller finishes executing code, AngularJS compares everything in the $scope to its previous values. If they’ve changed, it updates the DOM.

AngularJS cannot know whether it needs to execute the function again because it doesn’t know what the function does, so it executes its code every time it has to update the template. What if your function is executed hundreds or thousands of times on a template? What if the function does a non-trivial computation? That would be very slow!

I asked around how AngularJS developers get around this and apparently the best answer is to cache the result of the function yourself in a different variable. But if you do that, you’ve got more than one source of truth for that value. If you ever update the Room’s dimensions, how do we guarantee that the area property will be updated too?

I was pointed to an AngularJS function called $scope.$watch that allows you to watch an expression and execute some code when it changes. The problem is that the $watch function belongs to the $scope and NOT the Room. If you had an array of Room instances for example, you can’t watch them all without looping through them all constantly.

What if the same Room object instance existed in multiple controllers? You’d have to have the $watch in every controller which would mean a lot of unnecessary recalculations. Good luck debugging issues if you take that approach! Talk about a maintenance nightmare!

Reusing object instances

AngularJS makes it much harder to reuse object instances than Ember does. In an Ember template for example, you can link to another route using the {{linkTo}} helper:

<ul>
{{#each user in users}}
  <li>{{linkTo 'users.show' user}}Show {{username}}{{/linkTo}}</li>
{{/each}}
</ul>

Here, we’re looping through a list of users and creating a link to show that particular user. If you hovered over the link, you’d see something like /users/show/123 if your routes were set up properly. However, when you click the link, Ember actually passes the reference to the user through to your other route.

Ember’s router is smart enough to not have to resolve the user by id again if it already has the user object in memory. It just makes use of the object it already has. In AngularJS, every time you visit a route, it passes an id and has to resolve it in your controllers.

One of the great advantages of long lived browser applications is you can reuse objects as the user navigates around. AngularJS doesn’t follow this philosophy; it encourages you to throw away what you already had and find it again (probably from the server!).

Another consequence of this is that if you ever end up with two instances of the same User in memory, you’ve violated the single source of truth again!

Conclusion

I think it’s clear at this point that Angular’s focus on simplicity has some serious consequences. There are workarounds for some of these issues that you can implement yourself in your project with great discipline, but ask yourself this: are all developers on your team going to follow the same conventions? Additionally, if you add all sorts of extra constructs to AngularJS to make it work like Ember, why not just use Ember in the first place?

Due to it’s lack of conventions, I wonder how many Angular projects rely on bad practices such as AJAX calls directly within controllers? Due to dependency injection, are developers injecting router parameters into directives? Are novice AngularJS developers going to structure their code in a way that an experienced AngularJS developer believes is idiomatic?

In fact, what is idiomatic AngularJS? None of the examples or blogs I read through demonstrated how to reuse object instances, for example. Is that just not done in AngularJS applications?

Ultimately, I think you should examine your application’s goals. Do you want to build something that pushes the boundaries of what people expect from the web? Is your application going to be super simple, or do you want to add powerful features and maintain it well over time?

If you’re serious about front end development, I advise you to take the time to learn Ember properly. Once you figure out how all the pieces fit together, you’ll won’t be able to live without them.

Final Note

If you know Angular and I’ve written something wrong here, please contact me to let me know! I’d love to revisit or correct any mistakes or omissions.

I'm in New York City offering Ember.js training with Erik Bryn on May 22 & 23. Learn more!
View the full article to comment on it

Ember RC5 Upgrade Notes

Jun 9 2013

Recently, the Ember.JS team released two release candidates in succession. First came RC4 with a bunch of improvements and functionality, but it included a couple of performance regressions. It was promptly fixed with Release Candidate 5.

All users are encouraged to get their apps up to speed on the latest candidate as Ember approaches its 1.0 release.

We did encounter a few gotchas when we upgraded Discourse so I thought I’d write up our experiences in case it helps anyone else.

The Obvious One

The most obvious thing that broke in Discourse was anticipated, as it was covered in the RC4 Upgrade blog entry.

Previously, if you had a model hook in a router, it would always be set as the model (and content) property of your controller. This would happen even if you defined your own setupController method. There was a flaw with this automatic behavior however; if for some reason you didn’t want to set your model, there’s no way you could do that.

So as of RC4, if you define a setupController method, you have to explicitly set controller.set('model', model). This was fairly easy to audit in the Discourse source. I think we had about half a dozen routes that had model hooks but weren’t setting it ourselves. It took about 20 minutes to find them all and upgrade. Not so bad!

Creating Child Views Manually

Once our models were implemented, we started receiving a lot of deprecation warnings on our use of defaultContainer. There was a helpful link provided in the deprecation warning to a gist with a longer explanation.

We had some places in our code base where we were dynamically creating views and pushing them into a ContainerView. A good example would be the bar of buttons at the bottom of a topic. We’d have some code like var btn = Discourse.LoginButton.create({topic: topic}) and then this.pushObject(btn).

The issue with this is the views we were creating were not wired up properly. The call to create() was not correctly establishing the link between the new child view and the parent view. The solution is relatively simple. When creating child views, use the createChildView method:

// old way: var btn = Discourse.LoginButton.create({topic: topic});

// new, correct way:
var btn = this.createChildView(Discourse.LoginButton, {topic: topic});

this.pushObject(btn);

Initializing State in didInsertElement

This last gotcha was totally our fault, and was the reason we had to roll back RC5 shortly after deploying it. We’ve since fixed the issues and are redeploying our RC5 build tomorrow morning.

The didInsertElement hook is great if you need to work with a view once it has been inserted into the DOM. A typical use of it is for using a jQuery plugin or selector that needs your view to be present.

Unfortunately, we had some places where we used it to initialize state that belonged in the controller. In particular, the code we used to track which posts a user had read.

Previously, Ember would destroy and recreate a TopicView if we navigated from one topic directly to another. In RC4/RC5, Ember re-uses views for performance and memory reasons. This is awesome and the right thing to do, but obviously didInsertElement won’t be called a second time when navigating to a new topic.

The solution here was to move the logic out of didInsertElement and into the setupController hook of the route where it belonged.

Make sure that code in your views is only concerned with the view itself! Keep all model and user state in your controllers and keep your views as lightweight and reusable as possible.

Ember-Testing appears!

RC5 includes some new functions to make testing much easier. Discourse has done a great job on test coverage for our server component, but the client side is severely lacking. As you can imagine, it means we get more regressions and bugs than we’d like in the front end.

Going forward, we’re going to start testing the heck out our Ember code using this new functionality. I’ll be writing up more about that as we implement it!

I'm in New York City offering Ember.js training with Erik Bryn on May 22 & 23. Learn more!
View the full article to comment on it

Organizing Data in Long Lived Applications

May 26 2013

Trade offs

As a developer you’re constantly faced with issues of choice: What library is best? What framework is best? What platform should we deploy on?

Most of the time there isn’t a clear winner. The decision you make comes down to a series of trade offs. Do you want to optimize for developer happiness or performance? Do you care more about platform maturity or cost?

One trade off Ember.js has made relates to how it favors long living applications.

Ember.js applications tend to have larger downloads on your first request. This is not a great trade off to make if you expect your user to bounce away quickly right after visiting your site. However, if you hope they will stick around longer and navigate to many different things (such as in a Discourse forum) it’s a big win.

Old Habits Die Hard

When implementing server side applications, the best approach is often to do as little as possible as quickly as possible, then free your memory for the next request. This approach works very well and is performant, but is incongruous with long running applications.

Recently the distinction between short lived applications and long lived ones has started to rear its head in the design of Discourse, so I thought I might discuss a mistake I think we’ve made and how we plan to refactor and address it in the future.

Case Study: A User Directory

Let’s say you want to implement a user directory. It will list the users of your application, and clicking on one will display an expanded view of their details.

The Server Side Implementation

If you were doing this on the server side, you would probably start by performing a query of all the users, and rendering an HTML page with their names and links to their details. If your user table was big, you might restrict your query to only the columns you cared about, for example (id, username, fullName, dateRegistered).

The user details page would take an id as a parameter, and would use it to query the database for additional columns and return them all as a nice HTML document.

When developing server side applications, you try to share as little state as possible between requests. The server’s philosophy might be summed up as “Forget about everything you know – I’ll tell it to you again.” For example, the user’s name is right there on the directory list, but when you ask for that user’s details the browser ejects it from memory and asks for it again by id.

While it does seem wasteful to throw away what the client already has in memory, the system clearly works: most web applications are built this way and function well. If your application is mainly a set of simple links that the end user will follow, it will probably work out okay.

This approach becomes much less efficient when you don’t want to go all the way back to the server just to update or change a tiny piece of your document. There is a “short lived” solution for that too. You can use jQuery and make Ajax calls, then only update the parts of your view that you care about. The issue here is the more you do this, and the more dynamic your application becomes, the harder it is to organize and maintain your code efficiently. Sprinkles of jQuery might work for some, but if your application is ambitious you’ll probably have more success with a client side MVC framework like Ember.js.

The Ember.js Implementation

At first the Ember.js implementation of the user directory seems similar. You’d implement a route that retrieves a list of user objects from the server in JSON and a handlebars template to render them.

In the template, you’d create a link to another route to display the user’s details:

{{#each user in model}}
   <li>{{#linkTo showUserDetails user}}{{username}}{{/linkTo}} - {{fullName}}</li>
{{/each}}

There is a major difference here between the server and client side approaches. When you link to a user this way in Ember.js, the reference to the User object you are displaying is actually passed through to your showUserDetails route.

In other words, the showUserDetails route doesn’t have to look up the user again or anything like that. It is literally pointing to the same object in memory that the user list was using. This is what I mean when I say Ember is designed for long lived applications. If you expect your app to be kept open for a while, you can re-use the same objects in memory that you already have!

This is awesome because if your showUserDetails route wants to show the fullName or other attributes we’ve already loaded, it can do it without contacting the server. If you hit the back button and click on another user, the server will not be contacted.

A Common Pitfall

When viewing a user’s details, there are probably going to be a lot more fields to display than the list had. It would be inefficient to query all of a user’s data just to display a list. What if each user had 30 columns including text blobs? Most of that data would be loaded and never seen… not to mention it would probably load quite slowly!

We knew this was an issue in Discourse from day one, so we did what we thought would be reasonable: we’d return lightweight User objects with only a few of the fields loaded. The user list route would display them with the appropriate links. When the showUserDetails route loaded, we’d ask the server for the additional fields, and put them into our object.

This works, and is what you’ll find in most of the Discourse codebase right now. We’ve found though that it becomes very difficult to manage. Given any instance of a User object, how do you know if the extra fields have been loaded?

  • One approach is to force a more detailed User object to load when the route is entered, but that avoids the advantages of long lived applications. Also you’d need multiple code paths for the different styles of JSON, perhaps BasicUserSerializer and DetailedUserSerializer, which gets messy fast.

  • Another approach is to use a field like detailsLoaded to keep track of whether we have the details. If the field is false, we load them and set it to true. This works but is also annoying to work with. You still need multiple serializers, and now you’re putting data in your object which solely exists to recall whether other data is present.

Proposed Solution: Split up the Object

What if we thought of UserDetails as a separate entity, that is associated with the User via a “has one” relationship? The user list would use a single JSON serialization path, UserSerializer. When the details need to be loaded, they’d ask the server for them as a singular resource that would only include the fields it needed: UserDetailsSerializer. Once loaded once, the relationship would be established inside the user object.

With this approach it would be easy to show a result to a user right away, as well as a message while the details are loading:

<div>Username: {{user.username}}</div>
<div>Full Name: {{user.fullName}}</div>

{{#if user.details}}
  <div>Bio: {{user.details.bio}}</div>
  <div>Birth Date: {{user.details.birthDate}}</div>
{{else}}
  Loading user details!
{{/if}}

Thinking Forward: Identity Maps

If you’re working with a server side API, you’ll inevitably end up with code paths in your app that don’t have a reference to an object but know it by id or another identifier. In this case, it’s all too easy to naively load two instances of the same object into your browser’s memory which is wasteful and error prone.

In the future, we plan to add an identity map to Discourse that will ensure that multiple lookups by id will always reference the same object in memory. Before contacting the server, the identity map will be checked for the object we want in case we already have it around.

Another advantage to the solution above is it fits in very well with an identity map. The id for retrieving a user’s details will be the same as the User itself. We can share a lot of code, use less memory and avoid common bugs and logic with unloaded data.

It’s all too easy to try and map your client side application 1:1 with your server side API. However, you should take a step back on a regular basis and consider whether you are taking full advantage of the tools at your disposal.

Programming is often implementing something that works, but discovering a better approach along the way. This is one example of that in Discourse, but I’m sure there are many more. We love getting contacted about new and better approaches to our code base, especially when it comes with pull requests :)

I'm in New York City offering Ember.js training with Erik Bryn on May 22 & 23. Learn more!
View the full article to comment on it

Using Ember.js Part 3: Custom Views

Apr 1 2013

This article belongs to a series of tutorials about Ember.js and Discourse:



Important Update: The preferred way to do this is now using Ember Components.

The concepts in this tutorial still work, but the Hotness control created below would be better created as a proper component now that Ember has support for it. (They didn’t exist when this was written.)


Who needs views?

In an Ember application, the “View” part of your MVC will often just be plain old handlebars templates. You might have noticed that in the first two parts of this tutorial series, I created Controller classes but I didn’t have to create equivalent View classes.

So when is a View necessary? The Ember View Guide explains it nicely:

Views in Ember.js are typically only created for the following reasons:

  • When you need sophisticated handling of user events
  • When you want to create a re-usable component

Creating a reusable component is one of the most interesting things you can do in an Ember app. Let me show you an example of one I added to Discourse recently.

The “hotness” control

In Discourse, if a moderator clicks ‘edit’ on a category, they are presented with a modal that looks like this:

Editing a Category

The “Hotness” attribute is there to allow the moderators of a site to choose the topics they want featured on the “Hot” list. The idea is that categories that have a higher hotness will appear more frequently than those with a lower hotness.

As you can see, our scale goes up to eleven:



Embedding a View

You can embed a view in any handlebars template by using the {{view}} markup. Here’s how we can include a custom control called Discourse.HotnessView in our edit_category template:

{{view Discourse.HotnessView hotness=hotness}}

The hotnessBinding attribute tells Ember that we want to create a binding between our control and the category’s hotness property. If the category model’s hotness changes, the control will be updated to that value automatically. Conversely, if the control updates the property, the category model will be updated to the new value as well.

Implementing our View

To implement our view, we’ll create a file called hotness_view.js and put it under discourse/app/views in our javascripts folder.

Let’s start with something basic:

Discourse.HotnessView = Discourse.View.extend({
  classNames: ['hotness-control'],
  templateName: 'hotness'
});

If we create a view like this, Ember will render the ‘hotness’ handlebars template where we added our {{view Discourse.HotnessView}} markup.

If you open your web browser’s inspector you’ll notice that all views are rendered into HTML as <div> tags. (You’ll also see a bunch of views you didn’t create. All handlebars templates end up in views in Ember’s internals.) You can also change the type of tag Ember creates by adding a tagName property, but in this case a div will work just fine.

Ember allows you to add custom class names to the div container by using to the classNames property. In our case, we wanted our hotness view to have a class name of .hotness-control for styling purposes.

We can now implement a template for our view. Here’s how our HTML should look:

<button value="1">1</button>
<button value="2">2</button>
<button value="3">3</button>
<button value="4">4</button>
<button value="5" class="selected">5</button>
<button value="6">6</button>
<button value="7">7</button>
<button value="8">8</button>
<button value="9">9</button>
<button value="10">10</button>
<button value="11">11</button>

The selected class will render current hotness button in red.

Now we find ourselves in a bit of a quandary: Handlebars has a really useful {{each}} helper for iterating through a list of items, but in this case our items are simply a number range.

We could model this by creating an array of objects in our view to represent numbers 1 through 11. We could then use {{each}} to iterate through them all, but it seems quite wasteful to allocate a bunch of objects when all we’re doing is listing basic numbers.

Handlebars is great for rendering most things you throw at it, but this is one of the few cases where it feels like you’re fighting against the abstraction it provides. Fortunately, there’s a way we can avoid using handlebars altogether for our view.

Custom Rendering

If you create a method called render in your view, Ember will use its result instead of a template for rendering. It will be called with a buffer that accepts a push call with a string value. Here’s an example:

Discourse.HelloView = Discourse.View.extend({
  render: function (buffer) {
    buffer.push('hello');
    buffer.push(' eviltrout');
  }
});

If you embedded it using {{view Discourse.HelloView}} you’d see “hello eviltrout” instead of a handlebars template.

Let’s use this render method to create our buttons, adding the selected class where necessary:

Discourse.HotnessView = Discourse.View.extend({
  classNames: ['hotness-control'],

  render: function(buffer) {
    for (var i=1; i<12; i++) {
      buffer.push("<button value='" + i + "'");
      if (this.get('hotness') === i) {
        buffer.push(" class='selected'");
      }
      buffer.push(">" + i + "</button>");
    }
  }
});

And now if we reload our page, we’ll see our hotness control! The correct button will be highlighted thanks to a comparison with the hotness property of the view, which is bound to the hotness property of our model.

Potential Drawbacks

Rendering using the buffer like this can be quite useful, but it does some tradeoffs.

The first is that your code will be uglier. Appending strings is no where near as easy to read or write as a simple handlebars template. If you want to divide up responsibilities on your team between front end developers and designers, you’ll probably find that they are much more comfortable changing a handlebars template than the above.

The second is you have to remember to escape user supplied values yourself to avoid XSS issues. You can do this by including the handlebars escape function and calling it (thanks @krisselden):

var escape = Handlebars.Utils.escapeExpression;
buffer.push(escape(user_value));

The third is that your bound properties wont automatically update. Consider this: what would happen if you changed the hotness property within your category model? Since it’s bound to the HotnessView the hotness view will receive the updated value, but it won’t know to render again. We’ve lost some of the magic that makes Ember a pleasure to work with.

There’s a way around this. We can add the following method to Discourse.HotnessView:

hotnessChanged: function() {
  this.rerender();
}.observes('hotness')

The hotnessChanged method is now set up as an observer on the hotness property of the view. Whenever the hotness property changes, the observer will be called. In this case, all we want to happen is for the view to render again. this.rerender() tells Ember to do just that.

Now our control will properly update if the hotness changes.

An Aside: Rendering Performance

There is another benefit to rendering controls using the buffer rather than handlebars: it can be considerably faster. Ember is never quite sure what properties in your template will change and how frequently that will happen. By default, it assumes anything can and will change, and spends a considerable amount of rendering time setting up the structures it needs to observe them.

This is less pronounced on simple templates with few properties, but on large templates with thousands of properties you might start to notice.

There are cases where, if you know that your properties don’t need to update, you can take advantage of the performance of buffer based rendering. It will make your code uglier and less flexible, so I suggest you think twice before converting your handlebars templates to buffer.push calls.

Responding to Button Presses

The last thing our view has to do is respond to clicks so we can update the hotness property when the user clicks on a new number. The other powerful aspect of Ember views is they expose user events that you can deal with in a clean and elegant way. For example, we can define a click method like so:

click: function(e) {
  console.log("The view was clicked! Here's the jQuery event:" + e);
}

It will be called whenever the user clicks on the view. If you’ve ever written jQuery code to handle events you should feel right at home.

Note: we didn’t have to create the jQuery binding to the click event. Ember knew we wanted it when we created the click method. This also means we don’t have to unbind the click event. You can let Ember do that automatically when the View is no longer used, which is great for avoiding programmer errors that leak memory.

As you can see, the click method is called with a reference to the jQuery event of what was clicked on. We can use this to figure out what button the user clicked like so:

click: function(e) {

  var $target = $(e.target);

  // Return if something in the View was clicked on that wasn't a button
  if (!$target.is('button')) return;

  // Set our hotness value to the value of the button
  this.set('hotness', parseInt($target.val(), 10));

  // Don't bubble up any more events
  return false;
}

And we’re done!

Now we have a nice looking reusable control in about 38 sloc.

In the future, we may allow users to set their own hotness preferences for categories to their own tastes. We could embed the same control on their user preferences using one line of handlebars. That’s pretty sweet!

If you’re the type who’s been following upcoming HTML standards, you might be familiar with web components. The great thing about the above implementation is that it provides an abstraction that can easily be refactored into proper web components when more browsers support them and the timing is right.

Happy coding!

I'm in New York City offering Ember.js training with Erik Bryn on May 22 & 23. Learn more!
View the full article to comment on it

Ember without Ember Data

Mar 23 2013

Ember Data is a persistence layer for Ember.Js. Unlike Ember, which currently has a candidate for a 1.0 release, Ember Data is still very much a work in progress. This has been a source of confusion for people who are learning Ember, as the two frameworks are complimentary but currently exist in different realms of stability.

Ember Data has ambitious goals, and it has come a long way in the last year. If you’re the kind of programmer who loves working on upcoming stuff, you might find it exhilarating. On the other hand, it is completely understandable if you’d want to avoid it. Deprecations and changing APIs can be frustrating and time consuming.

One thing that is not always clear to people starting with Ember is that Ember works perfectly well without Ember Data! Trust me on this: Discourse doesn’t use Ember Data for persistence and it’s working quite well. Moreover, using AJAX with Ember is something that is not difficult to do.

Ember Models that are just Objects

Ember includes an object model that most people with an OOP background should find familiar. A subclass of Ember.Object works very well for a data model.

Here’s what a class might look like to represent a link from reddit:

App.RedditLink = Ember.Object.extend({});

You could then easily instantiate it and use getters and setters to access its properties:

var link = App.RedditLink.create();
link.set('url', 'http://eviltrout.com');
console.log(link.get('url')); // http://eviltrout.com

If you like, when you construct your model instance, you can pass it a regular Javascript object with the properties rather than setting them one at a time:

var discourseLink = App.RedditLink.create({
  title: "Discourse",
  url: "http://www.discourse.org"
});

console.log(discourseLink.get('title')); // Discourse

Here’s how you’d bind those properties to a handlebars template:

Title: {{title}}
Url: {{url}}

Once bound to a template like this, if you called set on your model, it would automatically update the HTML.

Accessing Reddit via JSONP

Data models are a lot more exciting when you fill them real data. Let’s write a method that finds the links from a subreddit. Reddit provides a JSONP API that we can access via jQuery:

$.getJSON("http://www.reddit.com/r/" + subreddit + "/.json?jsonp=?", function(response) {
  // response contains the JSON result
});

The response from reddit’s API includes the colleciton of links under data.children, but their properties are under an additional data attribute. We can loop through them like so, creating instances of RedditLink as we go:

var links = Em.A();
response.data.children.forEach(function (child) {
  links.pushObject(App.RedditLink.create(child.data));
});
// links now contains all our `RedditLink` objects!

$.getJSON is an asynchronous call. It follows that our model’s finder method will have to be asynchronous as well. One common approach to dealing with this is to pass a callback function to our finder method. When the $.getJSON call finishes, it can execute the callback with the result. What happens, though, when you need to handle the errors? You’d have to supply two callbacks: one for the error callback and one for the success callback.

Promises

This is all much cleaner to do with Promises. Promises are objects you return from your functions. They contain a then method that you can call when the operation is complete.

The nice thing about this is you don’t have to supply your callbacks to your function - you just attach them to the Promise object that your function returns. It ends up being a lot cleaner and simpler to follow. Additionally, Promises can be chained, so that the result of one promise is only passed through to the next function in the chain once it is complete.

jQuery conveniently return promises from all its AJAX calls, so we can just make use of it. Here’s how our finder looks, returning a promise:

App.RedditLink.reopenClass({

  findAll: function(subreddit) {
    return $.getJSON("http://www.reddit.com/r/" + subreddit + "/.json?jsonp=?").then(
      function(response) {
        return response.data.children.map(function (child) {
          return App.RedditLink.create(child.data);
        });
      }
    );
  }

});

Notice that we’re returning the result of $.getJSON, but also calling then on it. This means that the Promise that our findAll method returns will eventually resolve to our list of RedditLink objects. Here’s how you could you could call it and log the results from the subreddit /r/aww:

App.RedditLink.findAll('aww').then(function (links) {
  console.log(links); // logs the array of links after it loads
});

Putting it all together

I’ve created a github project that puts all the code from this blog entry together. You can also try it in your browser.

The code for the application is quite short, which I think reflects Ember’s greatest strength: as a developer you have to write less code to get stuff done.

I implore you to not be scared off by Ember Data’s current state. Ember itself is quite stable, and it’s easy to get started with AJAX calls like this today.

Update - Jun 30 / 2013

I’ve updated the code to use Ember 1.0 RC6 and added a bunch more comments. The code is not exactly the same as above, but it has a bunch of new features and is still based on the same principles. Download it and try it out!

I'm in New York City offering Ember.js training with Erik Bryn on May 22 & 23. Learn more!
View the full article to comment on it

Adding to Discourse using Ember.js Part 2: Controllers

Mar 17 2013

Ember.Js + Client Side MVC

You might have heard Ember.JS described as a Client-Side MVC Framework, where MVC refers to “Model-View-Controller.” In the first part of our tutorial, we talked about how Ember.js uses convention over configuration to prevent developers from having to create boilerplate and get up and running quickly.

Previously, we created an adminReports resource to handle URLs in the form of /admin/reports/:type. Ember automatically looked for our class called Discourse.AdminReportsRoute. However, that’s not the only thing Ember looked for! It will also find Discourse.AdminReportsController and use that as our controller to handle that URL.

You might be thinking: “We never created an AdminReportsController though! What’s up with that?”

Ember did something very convenient for us. We didn’t define a controller, so it couldn’t find one when it wired things up. Instead, it created one for us and gave it the default behavior. And for our purposes the default behavior was enough, so things just worked and we had to write less code!

Controllers in Ember.JS

Controllers serve a few major purposes in an Ember.js application.

  1. To respond to user interactions: When a user interacts with a template, say by clicking a button, you need to declare a method that will respond to that action.

  2. To expose data to your templates: Usually you will be exposing one model or a collection of models to a template. The controller is responsible for making a model’s data available for display in your template.

  3. To maintain state outside your models: Sometimes you need to work with data that doesn’t have anything to do with your models. A good example would if a user clicked on a column heading to change the sort order of a table. You could store the current sort order in the controller as a property.

If you’ve used a server side MVC framework such as Rails before, you should know that Ember.js controllers work a little differently. In server side MVC, controllers lose all state between requests. If you set an instance variable in one controller method and then call another in another request, the variable won’t be there!

In an Ember.js application such as Discourse, your controllers stay around. If you set a property in a controller, it will be there as long as the controller is still in use.

The AdminReportsController

How did Ember know what data to expose to our template if we never created a controller? If you recall, in our AdminReportRoute, we had a method called model:

model: function(params) {
  return(Discourse.Report.find(params.type));
},

When we entered our route, the model function was called and returned a single Discourse.Report object. Ember then inferred that our controller was dealing with a single model (rather than say, an array of models), and created an ObjectController for us.

An ObjectController is very simple. It exposes all the properties of your model as properties on the controller itself. In our template, we were able to say {{title}} and the controller knew to route that property to our model.

Adding controller functionality

The default behaviors of Ember can last you a while. But what if we wanted to add a bar chart display of the data in addition to our tabular display? We’ll have to define our own controller to handle that.

Let’s create the controller Ember needs and put it in admin/controllers/admin_reports_controller.js

Discourse.AdminReportsController = Ember.ObjectController.extend({
  viewMode: 'table',

  // true if we're viewing the table mode
  viewingTable: Ember.computed.equal('viewMode', 'table'),

  // true if we're viewing the bar chart mode
  viewingTable: Ember.computed.equal('viewMode', 'barChart'),

  // Changes the current view mode to 'table'
  actions: {
    viewAsTable: function() {
      this.set('viewMode', 'table');
    },

    // Changes the current view mode to 'barChart'
    viewAsBarChart: function() {
      this.set('viewMode', 'barChart');
    }
  }
});

Let’s do a quick run through. The first thing we do is declare a property called viewMode and set it to be ‘table’.

After that, we have two computed properties, viewingTable and viewingBarChart. As you can see, their implementation is very easy. They return booleans depending on the current view mode. The reason we do this is because handlebars is designed to be stupidly simple, so its #if statements can only respond to true or false values.

Finally, we have two methods, viewAsTable and viewAsBarChart that will be called when the user hits the buttons in the template.

A quick update to the model

In order to display a bar chart, we’ll need to add a percentage property to each row of data in our report. This is easily done in our find method.

Discourse.Report = Discourse.Model.extend({});

Discourse.Report.reopenClass({
  find: function(type) {
    var model = Discourse.Report.create({type: type});
    $.ajax("/admin/reports/" + type, {
      type: 'GET',
      success: function(json) {

        // Add a percent field to each tuple
        var maxY = 0;
        json.report.data.forEach(function (row) {
          if (row.y > maxY) maxY = row.y;
        })
        if (maxY > 0) {
          json.report.data.forEach(function (row) {
            row.percentage = Math.round((row.y / maxY) * 100);
          })
        }

        model.mergeAttributes(json.report);
        model.set('loaded', true);
      }
    });
    return(model);
  }
});

All we’re doing here is figuring out the maximum y property, and then updating each report object to have a percetage field which is their y divided by the maximum.

Finally, let’s set up our template:

{{#if loaded}}
  <h3>{{title}}</h3>

  <button class='btn'
          {{action viewAsTable}}
          {{bindAttr disabled="viewingTable"}}>View as Table</button>

  <button class='btn'
          {{action viewAsBarChart}}
          {{bindAttr disabled="viewingBarChart"}}>View as Bar Chart</button>

  <table class='table report'>
    <tr>
      <th>{{xaxis}}</th>
      <th>{{yaxis}}</th>
    </tr>

    {{#each data}}
      <tr>
        <td>{{x}}</td>
        <td>
          {{#if controller.viewingTable}}
            {{y}}
          {{/if}}
          {{#if controller.viewingBarChart}}
            <div class='bar-container'>
              <div class='bar' style="width: {{unbound percentage}}%">{{y}}</div>
            </div>
          {{/if}}
        </td>
      </tr>
    {{/each}}
  </table>

{{else}}
  {{i18n loading}}
{{/if}}

Near the top, you can see there are two <button> tags for switching the mode. The {{action}} helper wires things up so that when the user interacts with that button, the appropriate method on the controller will be called.

The next helper, {{bindAttr}} allows you to bind an HTML attribute to a property. In this case, we’ve bound the disabled property of the button tag to the opposite viewMode than the button represents. By doing this, the buttons will automatically enable and disable depending on the current state.

Try it out!

If you open up /admin/reports/active you’ll now see an interface that allows you to switch between views at the touch a button.

Visits by Day Think about all the code we didn’t have to write to make this work.

  • We have separated our concerns. We have a simple template that a front end designer can modify easily. The controllers and models are cleanly set apart.
  • Our code loads data asyncronously and only displays it when it is ready.
  • The user can switch the view style without having to contact the server for the data again.

In the next installment of this series, I plan to show how to create a custom view and the advantages it can give us!

I'm in New York City offering Ember.js training with Erik Bryn on May 22 & 23. Learn more!
View the full article to comment on it

Adding to Discourse using Ember.js Part 1: Routing and Templates

Feb 27 2013

This article belongs to a series of tutorials about Ember.js and Discourse:


I’ve heard from a lot of people in the process of learning EmberJS that there’s quite a jump from the Getting Started guide to actually contributing to a project like Discourse. I thought it might be useful to step through the creation of a new feature in detail and write out how it was done so others can get an idea of how things fit together. Let’s get started!

Feature Idea: A report of Visits by Day

It would be nice if there was a place in the admin section of Discourse that would show how many visits a forum receives in a day. We are already tracking this in the user_visits table in the database, but there’s no place in the user interface to view it.

Getting started: The URL Structure

When I start a new feature, I find it’s best to begin with its URL and expand outwards from there.

My first inclination would be to access the report at /admin/visits. That would certainly work, but what if we wanted to add more reports in the future? It’s' likely there could be some common code shared between them, so it makes more sense to separate them under a common resource such as /admin/reports/visits.

I now find myself thinking - are there commonalities between all reports that we can advantage of? They all have a title and some tuples of data to display at the very least. We could ask the server for a report of type visits, and it could return an object that the front end would know how to display.

If our URL was /admin/reports/:type (where :type is what identifies the report), for example, that gives us a lot of flexibility and potential for code re-use. Let’s go with that.

The Server Side

Since I’d like to focus this tutorial on the Ember side of things, I’m not going to go into detail about how the Rails portion of this feature is implemented. Let’s establish that if we make an AJAX request to the server at /admin/reports/visits.json we’ll get back a JSON response with the report data to be rendered in the following format:

{
  "report": {
    "type": "visits",
    "title": "Users Visits by Day",
    "xaxis": "Day",
    "yaxis": "Users",
    "data": [
      {"x": "2013-02-01", "y": 7},
      {"x": "2013-02-02", "y": 13},
      {"x": "2013-02-03", "y": 15},
      ...
    ]
  }
}

(If curious to see how the server side component was implemented, you may view the source on github.)

Adding our new Route

The first thing we have to do is tell our Ember app about the new URL. In Ember, this is known as routing.

The Discourse admin section client code is located in its own directory. The first file we’ll need to edit is routes/admin_routes.js. Let’s add a resource with a dynamic segment to match the URL we came up with. We’ll place the following line inside the admin resource declaration.

this.resource('adminReports', { path: '/reports/:type' });

What does the above do? Our EmberJS application now knows that whenever a user navigates to /admin/reports/visits, it needs to invoke the part of the application we’ve called adminReports to handle the request. There is a little magic going on under the hood so this is worth explaining in detail.

One thing EmberJS borrows heavily from Rails is convention over configuration. Instead of asking you to wire up every component manually, the Ember router asks you for a very small piece of information, in this case our adminReports string, and it will use that to look up the classes it needs to respond to the user.

There is a convention in Ember where a resource defined as adminReports will tell Ember to look for a class called Discourse.AdminReportsRoute. If you’ve created this class, Ember will use it when the user visits our URL.

Your Route classes should be short and simple. Ours will start by just rendering a handlebars template that we’ll fill in later with some data.

Let’s create a file in admin/routes called admin_reports_route.js and place the following content into it:

Discourse.AdminReportsRoute = Discourse.Route.extend({
  renderTemplate: function() {
    this.render('admin/templates/reports', {into: 'admin/templates/admin'});
  }
});

This tells Ember to render the template called admin/templates/report into our main admin template. Why into? Every view in our admin section has a simple menu up top that we want to display. We want our template to be rendered inside the template with the menu so the user doesn’t get lost. We’ll start by definining a placeholder template in the file: admin/templates/reports.js.handlebars:

<h1>This will display our report!</h1>

Now when we navigate to /admin/reports/active, we see this:

Basic Ember Template

Retrieving Data from the Server

Our feature would be a lot more exciting if it contacted the server to get some data. To do this, we’ll define a Report model. In Discourse, models are simple classes. Let’s create a file, admin/models/report.js and create a basic model:

Discourse.Report = Discourse.Model.extend({});

Discourse uses plain old jQuery AJAX calls to communicate with the server. Let’s add an AJAX call to find a report by type. We can use Ember’s reopenClass to add a find class method:

Discourse.Report.reopenClass({
  find: function(type) {
    return jQuery.ajax("/admin/reports/" + type, { type: 'GET' }.then(function(result) {
      return Discourse.Report.create(json.report);
    }));
  }
});

This find method makes an AJAX call to /admin/reports/:type on the server side and places the resulting data into an instance of Discourse.Report. Note that since AJAX is asynchronous, the find call will return a promise immediately and the report object will be created only when it finishes in the future.

Let’s now tell our Route to load the model when a user navigates to it. This can be done by implementing the model method. Here’s our new admin_reports_route.js:

Discourse.AdminReportsRoute = Discourse.Route.extend({
  model: function(params) {
    return Discourse.Report.find(params.type);
  },

  renderTemplate: function() {
    this.render('admin/templates/reports', {into: 'admin/templates/admin'});
  }
});

When the model method is defined, Ember will call it when the route is entered to retrieve the model and automatically make it available in our template.

Rendering the template

Let’s add a simple HTML table to display the results in admin/templates/reports.js.handlebars:

<h3>{{title}}</h3>

<table class='table'>
  <tr>
    <th>{{xaxis}}</th>
    <th>{{yaxis}}</th>
  </tr>

  {{#each data}}
    <tr>
      <td>{{x}}</td>
      <td>{{y}}</td>
    </tr>
  {{/each}}
</table>

Ember uses Handlebars to render its templates. The really cool thing about this is if the properties you’ve put into your template change, Ember is smart enough to update them in the web browser too. You don’t have to write any extra code to make sure the HTML re-renders, it just works!

If you change the title property of your report, Ember is smart enough to only update that part of the HTML. This is known as binding, and it’s at the core of what makes Ember a really useful tool for developing web applications. It allows you to cleanly separate your data from its presentation, and offers you a universal way to access it.

What’s next?

In the next part of this tutorial, I’m going to show how to set up a controller to respond to actions that the user performs in your template. In particular, I’ll show how you can present the same data that your application already has in a different way (a bar chart) without having to contact the server.

All of the above code is now checked in to our github repository, so feel free to browse it.

I'm in New York City offering Ember.js training with Erik Bryn on May 22 & 23. Learn more!
View the full article to comment on it

Older Posts

Generating IIFEs in Rails

Feb 25 2013

Infinite Scrolling that Works

Feb 16 2013

Why Discourse uses Ember.js

Feb 10 2013

Ember 1.0 preview upgrade notes

Feb 4 2013

Ember Router v2 Upgrade Notes

Jan 27 2013

Crawling the Downvote Brigades of Reddit

Jan 16 2013

How our users exploited concurrency and how we fixed it

Jan 10 2013

Turbolinks and the Prague Café Effect

Jan 6 2013

Just because you're privileged doesn't mean you suck

Jan 3 2013

I've been programming since I was 7

Dec 30 2012

Is Penny Arcade being ghost drawn?

Sep 30 2012