Yehuda Katz is a member of the Ember.js, Ruby on Rails and jQuery Core Teams; his 9-to-5 home is at the startup he founded, Tilde Inc.. There he works on Skylight, the smart profiler for Rails, and does Ember.js consulting. He is best known for his open source work, which also includes Thor and Handlebars. He travels the world doing open source evangelism and web standards work.

Using SproutCore 2.0 with jQuery UI

One of the goals of SproutCore 2.0 is to make it trivial to integrate the tools you’re already using together with SproutCore.

One way that we do that is to make it possible to drop a SproutCore app into a small part of your existing page. Greg Moeck did a great job demonstrating this functionality on the SproutCore Blog a couple of weeks ago, and I’d definitely recommend checking it out if you’re interested in learning more about embedding SproutCore 2.0 in an existing app.

Another complementary approach is to make it easy to integrate SproutCore with existing JavaScript libraries and tools. Because SproutCore 2.0 uses templates as the primary way to build your application, it integrates well with the tools you’re already using. In this post, I’ll show you the hooks you need to integrate SproutCore with anything you want, and then show you how to do a general-purpose integration with jQuery UI.

Quick Refresh: Handlebars Templates

First of all, you can take any piece of HTML and attach it to a SproutCore 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 a SproutCore view, which will define the sources of each of the properties used in {{}}}.

<script type="text/html">
{{#view Yehuda.BusinessCard contentBinding="Yehuda.businessContent"}}
  <div class="card">
    <p class="name">{{content.salutation}} {{fullName}}</p>
    <p class="address">{{content.streetNumber}} {{content.street}}</p>
    <p class="region">{{content.city}}, {{content.state}} {{content.zip}}</p>
  </div>
{{/view}}
</script>

Wrapping the HTML snippet in a <script> tag tells SproutCore to render it using its template engine. You’d normally get the {{}} properties from a controller or other data source, but let’s define a view with the values baked in for now:

Yehuda.BusinessCard = SC.View.extend({
  // fill in the content in the template with contentBinding
  content: null,
 
  fullName: function() {
    return this.get('firstName') + ' ' + this.get('lastName');
  }.property('content.firstName', 'content.lastName')
});
 
Yehuda.businessContent = SC.Object.create({
  firstName: "Yehuda",
  lastName: "Katz",
  salutation: "Mr.",
  streetNumber: 300,
  street: "Brannan",
  city: "San Francisco",
  state: "CA",
  zip: "94107"
});

If we reload the page, we will see a static business card with my information in it. If we update my content with Yehuda.businessContent.set(key, value), SproutCore will automatically update the HTML for you. If you update any property, including firstName or lastName, which are used only as dependencies of fullName, SproutCore will automatically handle updating the HTML for you.

didCreateElement

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 SproutCore has created. For instance, let’s say we want to zebra stripe the three lines in our business card once it has been create (note: you probably would not use JS to zebra stripe in real life).

Let’s extend our view:

Yehuda.BusinessCard = SC.View.extend({
  // fill in the content in the template with contentBinding
  content: null,
 
  fullName: function() {
    return this.get('firstName') + ' ' + this.get('lastName');
  }.property('content.firstName', 'content.lastName'),
 
  didCreateElement: function() {
    this._super();
    this.$("p:even").addClass("even");
  }
});

First of all, you will want to call super, to ensure that any hooks in parent classes get called. Second, all SproutCore 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.

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

jQuery UI

We can use these hooks to build some basic integration with jQuery UI. I’ve written a demo that shows how to connect SproutCore bindings to jQuery options at http://sc20-jqui.strobeapp.com/. You can also check out the annotated source code.

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 SproutCore’s binding and event system.

You can get started with the SproutCore 2.0 developer preview by downloading the starter kit.

Until next time!

11 Responses to “Using SproutCore 2.0 with jQuery UI”

Thanks for the writeup!

Just a heads up getting a “TypeError: defineProperty is not supported on DOM Objects” @ sproutcore-2.0.a.4.js:1741 on Safari. Working fine on Chrome.

With Opera 11.11:

Uncaught exception: TypeError: ‘Object.create’ is not a function

Error thrown at line 3773, column 4 in meta(obj, writable) in http://sc20-jqui.strobeapp.com/js/libs/sproutcore-2.0.a.4.js

@nicholas +1

Awesome. Looks like didCreateElement changed to didInsertElement on Jun 17, though, if anyone else runs into the problem I did.

https://github.com/sproutcore/sproutcore20/commit/f62a9f1cd98c8dcf0ee1be0eacd2a67d13278248

Hi,

Thanks for your great work. I am wondering if it is possible to call SC.Handlebars.compile(template) manually in the case of extending jQueryUI widgets? I do have some restriction to load the template within document.ready function, which is too late, I believe, to get compiled by the library. I tried to manually compile in the shell but I have got this error:

TypeError: Cannot read property ‘view’ of undefined

And I am just not sure if SproutCore does allow any control on the compile process. Thanks again for your help.

What changes need to be made to get this working with SC2 beta 2?

Sorry answered my own question. Forgot didCreateElement is gone now.

Using latest Sproutcore 2.0 as of 3rd August, didCreateElement no longer gets called it seems, I got this working by overriding didInsertElement instead.

I also got an error from jQuery UI with the line that creates the widget, changing to the following works for me and seems simpler:

var ui = $(this.get(‘element’))[this.get('uiType')](options);

I was working with JQuery 1.8 and the above code threw an error: “Cannot find method _createWidget”.

For newbies like me, note that you have to use JQuery UI 1.9.

Paul Chavard took a stab at this a while back and I improved on it to some degree. It’s here if anyone is interested. http://workmanw.github.com/sproutcore-jui/

Leave a Reply

Archives

Categories

Meta