Luke Melia

personal

March 10, 2012

Using Ember.js with jQuery UI

Note: This post is a refresh of Yehuda Katz’s post of June 11, 2011, Using SproutCore 2.0 with jQuery UI. Thanks to Yehuda for his review.

Another note: Updated on 8/24/2012 to bring up to date to ember-1.0.pre from 8/3/2012.

No rest for the weary: Updated on 4/14/2013 to bring up to date to ember-1.0.0-rc.2 from 3/29/2013.

N.B. Ember 1.0 has shipped! I updated the repo on 9/20/2013 to move to ember-1.0.0 final from ember-1.0.0-rc.2. I also updated jQuery and jQuery UI to latest stable versions. No code changes were required in the example code or blog post.

One of the goals of Ember.js is to make it trivial to integrate the tools you’re already using.

One way that we do that is to provide hooks to interact with the DOM the way that you have learned to with jQuery.

Quick Refresh: Handlebars Templates

You can take any piece of HTML and attach it to an Ember view. You would typically do this in order to attach event handlers to the view or to define a function that computes how a particular value should be displayed. For instance, let’s say we have some HTML that shows a business card for a person:

<div class="card">
  <p class="name">{{salutation}} {{fullName}}</p>
  <p class="address">{{number}} {{street}}</p>
  <p class="region">{{city}}, {{state}} {{zip}}</p>
</div>

We can wrap this chunk of HTML in an Ember view, which will define the sources of each of the properties used in {{ }}.

<script type="text/x-handlebars">
{{#view App.BusinessCardView}}
  <div class="card">
    <p class="name">{{salutation}} {{fullName}}</p>
    <p class="address">{{streetNumber}} {{street}}</p>
    <p class="region">{{city}}, {{state}} {{zip}}</p>
  </div>
{{/view}}
</script>

Wrapping the HTML snippet in a <script> tag tells Ember to render it using its template engine. Let’s look at the view and controller implementation :

App.BusinessCardView = Ember.View.extend({
  // view will render with it's corresponding controller as the context
});

App.BusinessCardController = Ember.Controller.extend({
  firstName: "Yehuda",
  lastName: "Katz",
  salutation: "Mr.",
  streetNumber: 300,
  street: "Brannan",
  city: "San Francisco",
  state: "CA",
  zip: "94107",
  fullName: function() {
    return this.get('firstName') + ' ' + this.get('lastName');
  }.property('firstName', 'lastName')
});

If we reload the page, we will see a static business card with Yehuda’s information in it. If we were to use the console to update the content by executing App.__container__.lookup('controller:business_card').set(key, value), Ember will automatically update the HTML for you. If you update any property, including firstName or lastName, which are used only as dependencies of fullName, Ember will automatically handle updating the HTML for you.

didInsertElement

You can also define some code to run every time an element is rendered. You can use this hook to wire up any JavaScript library to the element that Ember has created. For instance, let’s say we want to zebra stripe the three lines in our business card once it has been created (note: you probably would not use JS to zebra stripe in real life).

Let’s extend our view:

App.BusinessCardView = Ember.View.extend({  
  didInsertElement: function() {
    this.$("p:even").addClass("even");
  }
});

All Ember views have a $ function, which is the normal jQuery function, scoped to the current element. You can also call this.$() to get back a jQuery object wrapping the element itself.

You can use this hook to do anything you want, allowing you to hook in any library you want. You would use this hook a lot like you’d use a jQuery(document).ready hook, but scoped to the view being created.

Ember also provides a willDestroyElement hook, which you can use to tear things down that you set up when the element was inserted. This is relatively rare, and is mostly used when interfacing with another toolkit that requires a teardown, or to tear down custom Ember observers.

jQuery UI

We can use these hooks to build some basic integration with jQuery UI. Yehuda and Tom Dale wrote a demo (which I’ve adapted for current Ember.js) that shows how to connect Ember bindings to jQuery options at http://lukemelia.github.com/jquery-ui-ember. You can also check out the annotated source code and the GitHub repo.

The most important thing to look at is the JQ.Widget mixin, which can be mixed into view classes to attach jQuery UI options and events to Ember’s binding and event system.

You can get started with Ember.js over at emberjs.com.

Until next time!

17 Responses to “Using Ember.js with jQuery UI”

  1. oskbor chimed in:

    Hi! Ive been trying out your excellent mixin for jQueryUI. Im trying to get draggable and droppable to work. Here is link to a fiddle to illustrate my problem: http://jsfiddle.net/Aqrrj/6/
    The App.Draggable generates an element that looks like this:

    How should I go about to insert something into the draggable div? I’ve tried {{view App.Draggable}}Drag Me{{/view}} but that gives an error. I’ve also tried
    adding this
    // didInsertElement: function() {
    // this.$().html(“Drag me”)
    // }
    to App.Draggable but that also didn’t give the expected results. I vould like to be able to bind the content in the div to something.

    I am new to all this (js, ember, jquery etc), so I hope what I am trying to do makes sense.
    cheers

  2. Roy Truelove chimed in:

    Hugely helpful, thanks Luke. Keep it coming – ember.js needs a lot more blog entries!

  3. Alex chimed in:

    I tried this with the latest Ember and latest JQuery-UI and I got this error:

    Uncaught TypeError: Object # has no method ‘_createWidget’

  4. lukemelia chimed in:

    I’ve just updated the repo to Ember 1.0-pre, jQuery 1.8, and jQuery UI master and and refreshed this blog post a bit.

  5. Ben chimed in:

    Hey I’m working on a project in ember and having some trouble with this.

    didInsertElement works fine with the items in the view when it is originally created, but I am adding items to the view through a lazy loader and didInsertElement is not being re-called so the new elements are missing the draggable. Any ideas?

  6. Ofer Nave chimed in:

    I though Ember (even 1.0-pre) still requires jQuery 1.7.2 and doesn’t work with 1.8?

  7. lukemelia chimed in:

    @Ben this can be tricky. the brute force approach would be to observe the collection and call rerender() on the view. Alternately, you can observe the collection and call the appropriate jQuery commands as new views are added.

    @Ofer I have heard that as well, but we are using master with 1.8.0 and haven’t had issues.

  8. tony chimed in:

    I am using your Jquey mixins for a dialogs. What i found is that in the template, the {{bindAttr}} helper works but the {{action}} helper does not. Any thoughts, on why?

  9. lukemelia chimed in:

    @tony: nothing comes to mind. If you extract into a JSFiddle showing the problem, I’d be happy to take a look.

  10. mathis chimed in:

    @Alex any resolution? I’m getting the same “Uncaught TypeError: Object # has no method ‘_createWidget’ “

  11. Mothra chimed in:

    Luke-great post… I’ve implemented a slider widget using your Mixin and in my view I am valueBinding to a property in my controller similar to your example with the Progress bar. What I am seeing is it seems to be binding one-way. Any time the ember property changes, I do see it reflected at the jquery ui widget. However when changing the slider on the interface, these value changes are not are not reflected to the Ember property. Is this expected given this code base? Any insight on how to make it bind both ways like the normal built in views do?

  12. lukemelia chimed in:

    @Mothra, It certainly should be possible to simulate 2-way-binding. I’d be happy to take a look if you put together a JSFiddle.

  13. Anonymous chimed in:

    Tony is right; even now (2013-03-05) {{action}} does not work.
    Wish I’d known that 5 hours ago. :’(

  14. Frontend architecture of the new jimu user interface » Aras' Blog chimed in:

    [...] simplicity of jQuery UI API and how extremely well documented it is. Luke Melia wrote a post about using Emberjs with jQuery UI. We use mixins to add jquery UI interactions to UI elements. For example, lets discuss some of the [...]

  15. Frontend architecture of the new jimu user interface chimed in:

    [...] simplicity of jQuery UI API and how extremely well documented it is. Luke Melia wrote a post about using Emberjs with jQuery UI. We use mixins to add jquery UI interactions to UI elements. For example, lets discuss some of the [...]

  16. Juarez P. A. Filho chimed in:

    A short and objective post… Nice to see this kind of example, I am going to take a deep look in the repo. I have a doubt, sometimes I want to use the *click* function inside of the view and after the user click in the view I want to redirect it to another area of the site. For example I have a list of posts and when the user click on it I want to update the quantity of clicks in this post and after save in the database I want to redirect the user to the /post/[id]. How can I do that in a effective way? I tried to achieve this but I have a bug because the transition is not waiting the Ajax request to be completed. Thanks a lot!

  17. Eduard chimed in:

    Thanks for constantly updating this one!

Leave a Reply

LukeMelia.com created 1999. ··· Luke Melia created 1976. ··· Live With Passion!