Ember can React

This is a follow-up post to the talk that Mattia and I did at Toronto Ember on December 4th, 2014 entitled Ember can React. In that talk we explained how Ember could be used in the same events up, bindings down way that React is so often utilized. In this post I’ll discuss the task of getting Ember to play nicely in an existing DOM, and walk through an approach for doing so.

React is HOT, so hot, I just couldn’t help myself but give it a whirl. I’m using it on LCBO API to spruce up the homepage with a live API explorer:

Okay, okay, maybe it wasn’t just the hype that sold me on React. The HTML portion of LCBO API is generated by Middleman, so I needed a way to add JavaScript functionality to an existing page — it seemed like a nicely contained use-case to give React a try.

Ember can do this since forever ago, and no, not just one Ember application per-page, it’s possible instantiate multiple Ember applications on one page, doing it is just not very ergonomic or obvious. Here’s an example of one possible way:

<!-- Ember needs a place for template data, if we were using a build tool
like Ember-CLI the templates wouldn't have to live in the DOM. React
developers will likely write JSX, and have it compiled to JavaScript as
part of their build process. -->

<script type="text/x-handlebars" data-template-name="components/my-widget">
  <p>This is my widget, it go: {{itGo}}</p>
</script>

<script type="text/x-handlebars" data-template-name="application">
  {{my-widget}}
</script>

<p>My Widget 1:</p>
<div data-component="my-widget" data-it-go="Wooo-Wooo"></div>

<p>My Widget 2:</p>
<div data-component="my-widget" data-it-go="Choo-Choo"></div>
// This is ONE way to do this, it's not THE way, or THE BEST way:
function injectEmberApp(container) {
  var App = Ember.Application.create({
    rootElement: container
  });

  App.Router.reopen({
    location: 'none'
  });

  App.MyWidgetComponent = Ember.Component.extend({
    itGo: $(container).data('it-go')
  });
}

$('[data-component="my-widget"]').each(function(i, div) {
  injectEmberApp(div);
});

JSBin

In contrast, the React implementation to achieve the same result:

<p>My Widget 1:</p>
<div data-component="my-widget" data-it-go="Wooo-Wooo"></div>

<p>My Widget 2:</p>
<div data-component="my-widget" data-it-go="Choo-Choo"></div>
var MyWidget = React.createClass({
  render: function() {
    return (
      <p>This is my widget, it go: {this.props.itGo}</p>
    );
  }
});

$('[data-component="my-widget"]').each(function(i, div) {
  var itGo = $(div).data('it-go');
  React.render(<MyWidget itGo={itGo} />, div);
});

JSBin

The above examples demonstrate a scenario where you’d like to inject multiple instances of a component onto the same page. This is an advanced scenario for adding Ember (or even React) to an existing page. In this example, components are able to appear more than once on a page, we select all placeholder nodes with jQuery, and then instantiate a component (React) or application (Ember) in that node. You can see how it’s fairly trivial to manually attach React components or Ember applications to existing DOM nodes.

I think it’s pretty clear that the React implementation is a bit tighter, React.render makes it very obvious how you place a component into the DOM. It really does feel like React was forged from these fires, and it has a leg up because of that. Ember solves this problem as a technical side-effect, not because it was a primary use-case in its development (although to be clear it’s certainly no accident).

During our talk, Ember can React, Mattia and I discussed how once you get past the above boilerplate, doing things React-style in Ember is not only possible, but quite natural. We also realized how often we take for granted the niceties and robustness of Ember, just check out the talk to see that statement in action.

All of this said, it’s not hard to imagine a similar API in Ember via an addon or even as part of core that would make doing this sort of thing just as clear:

<div data-component="my-widget" data-attr-it-go="nice"></div>
var MyWidget = Ember.Component.extend();

$('[data-component="my-widget"]').each(function(i, div) {
  Ember.render(MyWidget.extend({ itGo: $(div).data('it-go') }), div);
});

You get the idea, and we can take it even further, perhaps Ember.render knew to pass every attribute declared on el into MyWidget as attributes:

<my-widget it-go="nice"></my-widget>
$('my-widget').each(function(i, el) {
  Ember.render(MyWidget, el);
});

And, and, maybe this instantiation code was just part of Ember, or some community supported addon and it “just worked” — it’s more than possible, even today. We can take it even further, what if when you booted Ember with a specific flag, it sniffed the existing DOM for tags that matched components registered in the Ember application and treated those nodes as normal components. Ember 2.0 proposes a lot of great changes that would make doing something like that very possible — I’m getting dizzy!

Now What?

Go forth and React, go forth and Ember, try a new tool, retry an old tool. It will do nothing but make you a better developer.

Un-Uploader

Uploads can be hard, even with Ember

A few weeks ago we decided to build a simple application to showcase what we consider to be a good workflow for uploading files that need some processing.

We were quite surprised that the most popular StackOverflow answer for handling uploads with Ember Data is to serialize them inside the model as a Base64 string. While this approach might be okay for small payloads, it falls on it’s face as soon as you want to upload something large. We wanted to actually solve the problem and utilize the potential of XMLHttpRequest2.

Our experience building apps shows that most times your app handles uploads you want to do something with them, most time you need to do some processing, almost all the times you want to store them in a safe place for backup.

Based on these assumptions our proposed solution involves a 3rd party storage service (S3 in our example), a webserver and a background processing system (we used Rails and Sidekiq) and a websocket implementation (we used Pusher). Most of these technologies (Ember included) can be swapped out with something else.

Check out the Demo App

Fork it on GitHub

Give the demo a try to see the experience your users can get with this kind of approach. We think there’s really no excuse to provide anything less than this level of UX.

This approach is useful for any operation that requires out-of-band processing, like payments and report generation.

Slides from our talk at Toronto Ember

Android for the web developer

Oh, hi there, I just noticed you there. Wathche doin? Working on JavaScript? Cool. What am I doing? Oh, just some stuff you wouldn’t be interested in. Honestly, I feel a little awkward talking about it. No you can’t see. DON’T LOOK NO DON’T.

ALRIGHT I’M WRITING JAVA OKAY!?

Are you happy now? I’m writing an app in Java. Java 6. Yes, from like a thousand years go, with Factories upon Factories upon Factories. Why? Cuz that’s what you do when you want to write an Android app. Here, let me show you.

Android for the web developer. (Part 1?)

Getting started

Can I use vim/emacs?

You can, but don’t punish yourself. Use Android Studio until you get comfy.

Okay, it’s installed, now what? Do I need a device?

Technically no, but if you want to stay sane, yes.

Does it have MVC?

Kinda, sorta. Remember the days before Ember and Backbone.js? When all you had was a big slimy ball of jQuery and everything seemed to glom itself together? Welcome back.

This jQuery metaphor has got legs, let’s run with it.

HTML => XML

On the web, we have HTML, it looks like this:

<!doctype html>
<html>
    <head><title>meow</title></head>
    <body>
        <p id=”oh_hi_there”></p>
    </body>
</html>

In Android, we have something similar for describing view layouts. This time it’s in XML:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_weight="match_parent"
    android:layout_height="match_parent">

 <TextView
    android:id="@+id/oh_hi_there"
    android:layout_weight="match_parent"
    android:layout_height="wrap_content" />

</LinearLayout>

More verbose, sure, but not so bad right?

CSS => styles.xml

In CSS, we declare styles and apply them to selectors:

<style type="text/css">
  #oh_hi_there {
      color: red;
  }
</style>

<p id="oh_hi_there">I'm red n stuff.</p>

In Android, it’s backwards, we define styles that the views will reference.

<resources>
    <style name="we_dont_have_selectors">
        <item name="android:textColor">#F00</item>
    </style>
</resources>

<TextView
    android:layout_weight="match_parent"
    android:layout_height="wrap_content"
    style="@styles/we_dont_have_selectors"
    android:text="I'm also red, n stuff." />

JavaScript => Java

It’s all similar, just less flexible and more verbose.

var foo = new Foo(); // JavaScript
Foo foo = new Foo(); // Java

Setting text dynamically:

// JavaScript
var view = document.getElementById("oh_hi_there");
view.textContent = "that was easy.";
// Java
TextView view = (TextView) findViewById(R.id.oh_hi_there);
view.setText("that was... something.");

Adding a click handler

In JavaScript we have anonymous functions for working with callbacks. In Java, we have anonymous classes that match an interface:

// JavaScript
view.on("click", function() {
  causeAHugeMemoryLeak();
});
// Java
view.setOnClickListener(new View.OnClickListener() {
 @Override
  public void onClick(View v) {
   causeAHugeMemoryLeak();
 }
});

There are 3 things that you need to learn immediately and accept.

  1. You must only do fast, drawing related work on the “Main” or “UI” thread.
  2. In order to do this you must learn at least a little about Threads and Threading.
  3. Many of tools that the framework gives you are broken and filled with lies.

More on that next time!

Avoiding Memory Leaks in Backbone.js

Backbone.js is a fairly minimal JavaScript framework when you compare it to its more full-featured cousins like Ember or Angular. It can be a rude suprise when Backbone suddenly leaves you on your own when you were expecting to have a helping hand. There are many gotchas surrounding sub-views for example that aren’t typically mentioned in the many TODO list examples out there.

It is very easy to find yourself in a situation where your views are leaking memory if you aren’t careful. Happily, with some recent additions to the framework and some good tools, we can identify these problems and patch them up.

The Setup

Let’s start with a model and a collection:

class Item extends Backbone.Model
  # ...

class Items extends Backbone.Collection
  model: Item

We want to show the items in a list with each item in its own view. Let’s create the list view:

class ListView extends Backbone.View
  className: 'list'
  tagName: 'ul'

  initialize: ->
    @collection.on 'reset', @addAll, this

  addOne: (item) ->
    view = new ItemView(model: item)
    @$el.append(view.render().el)

  addAll: ->
    @$el.empty()
    @collection.each(@addOne, this)

  render: ->
    @addAll()
    this

and the item view:

class ItemView extends Backbone.View
  className: 'item'
  tagName: 'li'

  events:
    'click' : 'remove'

  render: ->
    @$el.html(@model.get('name'))
    this

We want our items to update themselves when they are renamed:

class ItemView extends Backbone.View
  # ...

  initialize: ->
    @model.on 'change:name', @updateName, this

  updateName: ->
    console.log 'updateName'
    @$el.html(@model.get('name'))

  # ...

When an item in the list is clicked, we want to remove it from the DOM (not from the underlying collection for this contrived example).

class Item View extends Backbone.View
  # ...

  events:
    'click' : 'remove'

  # ...

Here is a working jsfiddle example.

Straightforward right? Well, it turns out we’ve just hit a pain point that many a Backboner has found before us: we’re leaking memory. While we remove our ItemViews from the DOM when they’re clicked, they’re still registered to the model’s change events and therefore can’t be garbage collected. Because the views can’t be collected, the DOM nodes they control can’t be collected either (they become ‘detached’). These views are now ‘zombies’.

There is a second problem. When the models change, the events will continue to fire on our zombie views, which can cause strange behaviour in our UI.

I’m going to take what I learned from Andrew Henderson in his post How to detect backbone memory leaks and apply it to our example.

Here, in our initial snapshot, we see 5 ItemViews have been allocated as expected:

5 ItemViews

After removing the first 3 items, I then rename all the items in the collection and we see that all 5 ItemViews still respond to the changes. In the second snapshot we also see 3 newly detached DOM nodes. This proves we’re leaking memory.

3 detached nodes

Backbone 0.9.9 to the rescue?

But wait you say, the new version of Backbone comes with .listenTo which will automagically unbind from event listeners and now we can go back to faceroll development mode. Sweet! Let’s check it out.

@collection.on 'reset', @addAll, this
  @model.on 'change:name', @updateName, this

becomes:

@listenTo @collection, 'reset', @addAll
  @listenTo @model, 'change:name', @updateName

See jsfiddle version 2

Running through Chrome again, the click events are now behaving as expected, we’ve taken care of our detached DOM nodes, and there are only 2 instances of ItemView now as we would expect. That’s pretty great for such an easy change, hats off to the backbone team for that one.

Let’s keep going though, if we now remove the ListView itself from the DOM we’ve got another problem:

ListView leaves garbage

We’ve removed the UL node from the DOM, but we’ve left the last 2 instances of ItemView zombified. They’re still responding to model events and their DOM nodes are detached.

My basic approach is that if a view creates another view, then it should be responsible for cleaning it up also. Let’s do that now. The plan is to fire an event on the ListView that ItemViews will listen for and call #remove on themselves.

class ListView extends Backbone.View
  # ...

  addOne: (item) ->
    view = new ItemView(model: item)

    # The item view will listen for the clean_up event on the list_view
    # and clean up after itself and remove itself from the DOM
    view.listenTo(this, 'clean_up', view.remove)

    @$el.append(view.render().el)
    # ...

  removeItemViews: ->
    # let the children know it's time to put away their toys.
    @trigger 'clean_up'
    # ...

  addAll: ->
    # clear out any existing ItemViews when resetting the collection
    @removeItemViews()
    # ...

  remove: ->
    # when the ListView is being removed, it must clean up it's children
    @removeItemViews()
    super()

Let’s check Chrome.

No more detached nodes

No more item views

No more lingering event handlers, no detached nodes, and no instances of ItemViews remain.

All done.

Leaks: plugged. Zombie scourge: put to rest.

Final jsfiddle

Related Reading