Archives for posts with tag: kvo

The first SproutCore interview I attempted with Eloqua’s Matt Grantham and Ryan Mudryk went well and it acquired a lot of viewership. Knowing that, I decided to test the waters again and try a second SproutCore interview this time with Michael Harris who created the SproutCore Sudoku game. Mike is consultant and local here in the Washington, DC area, so he and I met one day during lunch to discuss his game and SproutCore itself.

Read the rest of this entry »

A while ago I mentioned in a post that in order to “get” how the SproutCore framework works you really have to understand SproutCore’s key-value-observing (KVO) and binding paradigm since they are so central in how the rest of the framework works.

Looking back at that post, I realized that my explanation of KVO and bindings was too general and hand-wavy and may not make sense to a person new to SproutCore. In an effort to help all those out, I’m going back to the topic of KVO and bindings but this time making things (hopefully) more obvious and concrete.

Now bare in mind that KVO and bindings are big topics and there’s a lot to know behind the scenes. Therefore I’m going to be taking you down the path one simple step at a time. So, you know, brace yourself. Grab a beer while you’re at it.


Part 1: Theory is as Theory Does

Let’s first start out with a bit of background and theory. Now, now. No snoring in the back of the class ;).

When you normally work with JavaScript, you know that you can create an object pretty easily that consists of regular properties and methods like in the following ways:


/* A very simple way to create an object */
var user = {
  firstName: 'John',

  lastName: 'Doe',

  getFullName: function() {
    return firstName + ' ' + lastName
  }
}

/* Another, improved, way to create an object */
function UserObject(fname, lname) { /* a function acting as a class constructor */
  this.firstName = fname,
  this.lastName = lname
}

UserObject.prototype.getFullName = function() {
  return this.firstName + ' ' + this.lastName;
}

var user = new UserObject('John', 'Doe');

Pretty basic. When building a web-based application, or rich internet application (RIA) as people like to sometimes say now, you make lots and lots of objects in order to implement interesting functionality and modularize your work. Right? And when building your web app you no doubt have different visual components that display information about those objects and modify them.

If you’re following good design practices you probably even embrace the Model-View-Controller (MVC) architectural pattern to further structure your code into logical groups and ensure you decouple your domain model from your views using controllers. However, depending on how you tackle MVC you may end up writing a lot of plumbing/boiler-plate/glue code to get everything to work, such as making sure a model object is updated when you modify information in the view, syncing information between two or more views and so on.

Writing such code is annoying, time consuming and error-prone. It would be so much easier if you could have some mechanism that did most or all of the work to connect views, controllers and objects for you so you can focus on getting the real functionality done. Do I hear an “amen, brother” coming from you ;)?

Well wouldn’t it be great if you could just change an object’s property and any object that observes that property gets notified of the change automatically, but without having to write all the plumbing to make that happen? Yes. So what we want is to observe a property (or, rather, a key) and be notified when its value changes. Hmm… key… value… observing — Key-value-observing!

Let’s focus our attention on this observing term for a moment. If you’re up to par on your software design patterns, you’ve probably heard of the observer pattern written by the Gang of Four (GoF). The observer pattern is a great generalized solution that allows one object to observe (or listen for) changes or get notifications on another object, but in a decoupled way. Take a look at the following diagram that shows the observer pattern.

kvo-bindings-observer-pattern

See how the class Bar inherits the FooObserver interface? This decouples the Foo object from caring about the specific underlying type and only cares that an object inherits the FooObserver interface. For every object that inherits the FooObserver interface and registers with a Foo object, the Foo object will notify each observer after some change has occurred. Pretty cool, eh? But what does all this mean for the SproutCore framework? Well, as you may have guessed by now, SproutCore takes advantage of this observer pattern as a central corner stone towards making KVO and bindings a reality. Let’s go back to SproutCore now and see this observer pattern in action.


Part 2: Minding Your Ks, Vs and Os

All objects in SproutCore ultimately derive from SC.Object, and when you make your own class that derives from SC.Object is looks like the following example:


MyApp.User = SC.Object.extend({
  /* add your class's special properties and methods here */
})

The User class above now inherits all of SC.Object‘s properties and methods. But if you first shift through the code that makes up SC.Object (object.js in the frameworks/runtime/system directory) you don’t see any kind of observation logic. All the observation logic is actually contained within a mixin called SC.Observable (observable.js in frameworks/runtime/mixins directory). The SC.Observable properties and functions get added to SC.Object. And since that functionality is now part of SC.Object that means all objects that derive from SC.Object also get SC.Observable logic. Okay, great. Now that we’ve located the observation logic let’s dig in.

Although there is a lot of functionality in SC.Observable let’s focus on a select few functions, namely set, addObserver, removeObserver… Wait, what were the the last two functions called again?! addObserver and removeObserver. Doesn’t that sound awfully familiar? Yep. Okay, take a moment and look at the declarations for addObserver and removeObserver, you have the following:


addObserver: function(key, target, method, context)

removeObserver: function(key, target, method)

The addObserver method takes four parameters. The first argument is a key (a property) of the object we want to observer. The second argument is a target which is the the object that wants to be notified of changes to the given key (again, property). The third argument is a method that is to be called on the target so that the target is actually notified of changes to the key. The fourth argument, context, isn’t important for this post, but it is passed to the target when it’s method is called to help give additional information about the notification.

The removeObserver method is almost the same, but it takes three arguments instead of the four. And as you can guess the method is to remove a target’s observation of a given key.

By assigning a value to a SproutCore object’s property using the set method, set will assure that the object’s that are observing the given property are notified, which will happen either immediately or later on. I’ll get to what “later” means soon.

So this is good stuff. We now have some important concepts about KVO under our belt. Now its time to see what this actually means. What we’re going to do is create a very small SproutCore application to get some objects set up, and we’ll be using a browser’s JavaScript console to see what is happening in real time as we hook the objects together. Use Firebug for Firefox or the JavaScript console that already comes with Safari and Google Chrome.

Go ahead and create a new SproutCore application using the sc-init tool and call your application MyApp. Great. Now, to keep things simple so that we can follow along with what is happening, we’ll create two basic SproutCore objects. The first object is an object whose properties we will change. The second object will be observing the changes. Create two new JS files under the app/my_app directory and call them user.js and the second monitor.js. In the user.js file, enter the following code:


MyApp.User = SC.Object.extend({

  firstName: '',

  lastName: '',

  age: 0

});

And for the monitor.js file enter the following:


MyApp.Monitor = SC.Object.extend({

  notifyPropertyChange: function(sender, key) {
    console.log( 'property %@ set to %@ for object %@'.fmt(key, sender.get(key), sender) );
  }

});

Good. For the monitor object, we’re just going to be watching for changes to a user object and writing information about it to the JavaScript console. (Note that for the method notifyPropertyChange we could have equally not provided any arguments but still get notified, minus any information. As well, you can add on another two arguments, value and rev. The value argument isn’t currently used in SproutCore and rev is beyond the scope of this post).

Alright. It’s time to fire up your browser of choice and follow along in the JavaScript console. I’ll be using Apple’s Safari.

In your console, first create an instance of a User object like so:

var user = MyApp.User.create();

Now create an instance of a Monitor object:

var monitor = MyApp.Monitor.create();

Perfect. We want the monitor object to observe a property on the user object. Let’s make it observe the firstName property. We do this by entering the following:

user.addObserver('firstName', monitor, 'notifyPropertyChange')

So this now makes the monitor object observe the user’s firstName property. Now let’s see what happens when we modify the first name. Enter the following:

user.set('firstName', 'Joe')

If everything went okay, what did you just see happen in the console? Did you get something that reads like the following:

property firstName set to Joe for object MyApp.User:sc263

You did? Success! Congratulations you have successfully got the monitor object to be an observer of user object. You’re now on your way to understanding KVO!

If you want to know if a property of an object does have observers you can call the object’s observersForKey** method, like so:

user.observersForKey('firstName')

You’ll get back true since the property does have an observer. What happens if you change the value of the lastName property of the user object? Let’s find out. Enter the following:

user.set('lastName', 'Doe')

Nothing got outputted to the console. That’s because the monitor is not observing the lastName property; however, if you check the value of lastName it was updated properly.

We’ve got to the point where we can now see how the SproutCore framework is making use of the observer pattern to act as a building block for key-value-observing. Now we’ll look at what builds on top of KVO and the observer pattern: bindings.


Part 3: The World is Nothing but a Bowl of Bindings

I will fully admit that when I first crossed paths with SproutCore bindings concept I was a bit mystified about what it was and how they actually worked. So if you feel like you didn’t or still don’t get bindings don’t feel alone. That being said, after working with the SproutCore framework to do my work, I quickly became comfortable with the idea of why they are so darn useful. Let me see if I can walk you through it.

The central premise of a binding is to connect one object’s property with another object’s property and communicate changes between those properties. Really. That’s it. All we’re doing is keeping properties in sync. Take a look at the following picture.

bindings-basic-concept

Above we can see that on the left there is an object A that has a property named foo, and on the right there is an object B that has a property named bar. The binding object you see in the middle is what acts an the intermediary, or go between, in assuring that when foo is changed then bar is updated with the same value. And when bar is changed that foo is updated with the same value. We can see this in the following diagram:

bindings-how-it-works

Okay, that’s cool. The concept seems kind of trivial after you take a step back and look at it. And SproutCore is designed so that working with bindings to synchronize the values of properties is simple, such as in the following code:


var objA = SC.Object.create({

  foo: ''

});

var objB = SC.Object.create({

  bar: '',

  barBinding: 'objA.foo'

})

That’s all it took to bind the properties together. All we had to do was add barBinding as a property of objB and assign the value objA.foo to it. SproutCore takes care of the rest automatically. In fact, let’s give it a try! Remember the SproutCore app we made back when discussing KVO? Go ahead and reload the page if your browser is still has it open. Now open up the JavaScript console and begin by typing in the following:

var objA = SC.Object.create({ foo: ''})

We have objA loaded into memory. Enter the following into the console:

var objB = SC.Object.create({ bar: '', barBinding: 'objA.foo' })

Now we have objB loaded into memory and its bar property is bound to objA’s foo property. Fo’shizzle. If you do a get on either property they will both have empty strings, which is what we expect. Now let’s go ahead and change the value of foo in objA. Type in the following:

objA.set('foo', 'cat')

Go ahead and check the value of foo by calling objA.get('foo'). The value should be cat. And because foo is bound to bar that must mean that bar is cat too! Check by calling objB.get('bar'). Yes! We see that bar is now… an empty string?!? Oh no! What did we do wrong?! Remember back when I talked about KVO and I said that when you call the set method to modify the value of a property, the observers of the property can get notified either immediately or later? Well this is the later part I was refering too. Surprise!

When you use bindings in SproutCore they do transfer the value from one property to another but it is deferred. The changes that go through bindings actually get queued up. Why? Welcome to the world of SproutCore’s run loop mechanism. Yay, yet more to know ;).

I won’t say too much about the run loop since that’s a big topic in and of itself. However, all you need to know is that the run loop is a central device to coordinate how events get propagated and property values get changed using bindings, among other things. So what does this mean for us? It means that we have to kick the run loop to get things rockin’. Let’s go back to our JavaScript console. If you haven’t done anything after the last step we took (objB.get('bar')), then go ahead and type in the following:

SC.RunLoop.begin()

And now type this:

SC.RunLoop.end()

Finally, check the value of objB’s bar property by once again calling objB.get('bar'). Holy crap on a cracker! It worked! bar is now set to cat! As Cartman from South Park likes to say, “sweeeeeeet”. Since we’re on a role, let’s change the value of objB’s bar property by first doing the following:

SC.RunLoop.begin()

Now go ahead and change the value of bar by entering objB.set('bar', 'dog'). Finish with the following:

SC.RunLoop.end()

Now check the value of foo by entering objA.get('foo'). It’s dog! This is great. We see that the binding has actually synced the properties foo and bar.

While you may have this sense of warm, fuzzy feelings, you may also have this other thought in the back of your head saying what we did is very cool, but I don’t get how SproutCore really got the properties connected. All I see is this special property called barBinding. What did SproutCore actually do? If you didn’t have this thought rolling around in your noggin’ I’ll pretend that you did. Work with me here.

It’s time to pull back the curtains and see what’s going on behind the scenes that make this seemingly trivial binding mechanism work.


Part 4: Deeper Into the Binding Abyss We Go

In SproutCore bindings are objects just like anything else. No special magic here. That means you actually have to create an instance of a binding and set it up to connect properties together, but SproutCore takes care of that for you. And bindings work like other objects that just want to observe the changes to some other object’s property. That would mean, yep, that bindings are leveraging KVO. And if they are leveraging KVO then its a good bet that they are probably adding themselves as observers to an object. Are you recognizing a running theme going on?

Let’s go back to the SC.Observerable code in the observable.js file. If we look around the file a bit more you’ll come across a method called bind that has the following declaration:

bind(toKey, target, method)

This method is what you can use to do manual binding on an object’s key. If you read the comments for the method it says that this is the manual equivalent of doing the more traditional propertyBinding: 'property path' approach. Ah, interesting. Looking at the body of the method you’ll notice that a binding object gets created:


// Starting at line 1068 of observable.js (SproutCore v1.0 Beta)
var pathType = SC.typeOf(target) ;
if (pathType === SC.T_STRING || pathType === SC.T_ARRAY) {
  binding = this[toKey + 'BindingDefault'] || SC.Binding; // 1) Get the binding class
  binding = binding.beget().from(target) ; // 2) Now create the binding
} else binding = target ;

Basically we see that the binding is either being derived from a path (a property path) or it is the target argument. It’s the path we’re focusing on. I added comments just to make it a bit clearer. The given target (an object) is assigned to the binding’s “from” property. This is one end of the binding. What about the other end? Look further down the body of the method and you’ll see these lines of code:


// Starting on line 1075 of observable.js (SproutCore v1.0 Beta)
binding = binding.to(toKey, this).connect() ;
this.bindings.push(binding) ;

Above we now see the called object being passed to the binding’s to method. So the object is now assigned to the binding’s to property — the other end of the binding. The binding has a from and a to. This seems to imply direction. It does. With bindings we can control the flow of information by manipulating what is actually assigned to a propertyBinding property. However, for now, let’s not worry about manipulating flow and data being passed through a binding. We’ll just keep focusing on the basics. The default binding used will make sure that two properties are always in sync with each other.

Right after a binding’s to property is set the final thing to do is call the binding’s connect method. Despite what you might think, the call to connect doesn’t bind properties together immediately. Instead, the bind object is passed to a queue to then later connect properties together. If you’re asking if this has anything to do with SproutCore’s run loop mechanism, you’d be right.

The real guts and the glory happens in another method called _connect which is intended to be private. You can find the method starting on line 347 in the observable.js. There’s a bunch of code going on here, but just laser in on two lines: line 379 and line 384, where you’ll see the following:


SC.Observers.addObserver(path, this, this.fromPropertyDidChange, root) ; // 379

SC.Observers.addObserver(path, this, this.toPropertyDidChange, root) ; // 384

Notice anything that stands out like a sore thumb? It would be the addObserver method. Hello old friend. We’re right back to where we started. Yep. The binding is just leveraging KVO and the observer pattern so it can be notified when either a particular property on the from object changes or when a property on the to property changes. There’s obviously a lot of code to make this all happen, but it rests on the fundamentals. There is no spoon.

That was a lot to take in and we haven’t even had a chance to do anything in part 4 of this blog post. Well, guess what? Let’s jump back into our JavaScript console and take the bind method for a ride.

First, reload your web application we created earlier on so we can start fresh. We’re going to be using our trusty objA and objB that we’ve used in the last few coding exercises in this blog entry. Create objA like so:

var objA = SC.Object.create({ foo: '' })

And go ahead and create objB like so:

var objB = SC.Object.create({ bar: '' })

Notice that we didn’t include the barBinding this time because we’re going to manually create the binding with the bind method, which we’ll do right now:

objB.bind('bar', 'objA.foo')

Great. We’ve got the binding preped. Let’s go ahead and modify the value of foo:

SC.run(function() { objA.set('foo', 'cat') })

The run method is just a more convenient way of executing the run loop with a given anonymous function. If we check the value of bar and foo, what do we get? cat! Awesome. The manual binding worked. Now let’s go the other way:

SC.run(function() { objB.set('bar', 'dog') })

And what do we get when we check the values of the properties? dog! We are at zen with the universe.


Part 5: The Long Journey Home to propertyBinding

Great we’ve figured it all out. The observer pattern, KVO and bindings. It took some time but hopefully you found the journey worth it. Good luck and thanks for all the fish.

… But wait! There’s one more thing we haven’t figured out. Just how does SproutCore detect the propertyBinding on an object and covert it into a actual binding object? Ah, yes. Let’s tackle this final puzzling question.

Jump over to the SC.Object in the object.js file and take a look and the class’s initialization method init starting on line 446. The body of the method is pretty small but there’s definitely one import line that speaks volumes to us: this.initObservable(). Initialize observable, eh? Hmm. Okay, now let’s jump back over to the SC.Observable mixin in the observable.js file and go to the initObservable function. Looks pretty meaty, right? Not to worry. We’ll just go to line 843 where bindings get created. And here’s the code:


this.bindings = [];
if (keys = this._bindings) {
  for(loc=0;loc<keys.length;loc++) {
    // get propertyKey
    key = keys[loc] ; value = this[key] ;
    var propertyKey = key.slice(0,-7) ; // contentBinding => content
    this[key] = this.bind(propertyKey, value) ;
  }
}

The logic above is iterating over the object’s array called _bindings which is a pre-compiled list of properties that were already determined to have a key with a suffix of “Binding”. The suffix “Binding” is sliced off from the key to give us the actual property name. With the key and it’s assigned value, the object’s bind method is called to set up the binding. Okay, great. This partly answers our question of how the bindings are set… but where did this pre-compiled array of properties that have keys with “Binding” as a suffix come from? More to discover! And you thought this would be just a walk in the park ;). We’re almost there. There’s one final piece to the puzzle.

When an object is created using the SC.Object‘s create method, you can extend it with your own properties and methods. As well, when you extend a class to create a new class you use SC.Object‘s extend method. Okay, you’re asking yourself so what? Both of these methods are two sides of the same coin to our final answer.

When you extend a SproutCore class, the extend function does some interesting stuff. One of those interesting things is to create a new function that will be the class’s constructor, which if you go to line 240 in object.js you will see it. In the constructor it makes a call to SC._object_init. SC._object_init is the actual method that gets called first when you create an instance of a class in SproutCore. The method will in turn call the init method that will initialize the object’s observers. We’ll come back to SC._object_init in a second. Further down in the extend function is another interesting statement on line 256 where there is a for-loop making calls to SC._object_extend. What’s SC._object_extend? Just wait. Switching back to SC._object_init, go to line 376. What do you see? Why it’s another for-loop making calls to SC._object_extend. This is the final piece to the puzzle.

Go to the function SC._object_extend on line 37 in the object.js file. If you read the comments for the function you’ll see a statement that says the following:

prepping a list of bindings, observers, and dependent keys

Preparing a list of bindings? Ah-ha! A clue. There’s a lot going on inside of SC._object_extend but the function is basically taking the properties and methods from one object and sticking them on to the object that is to be extended all while doing some special processing. Take a look at line 65 that has the following statement:

var bindings = base._bindings, clonedBindings = NO;

Yes! We’ve found were the base object’s _bindings array is added. Now where does the array get its content from? Inside the for-loop that iterates over the keys, take a look at lines 90 to 101 where you’ll see the following:


// Possibly add to a bindings.
if (key.slice(-7) === "Binding") {
  if (!clonedBindings) {
    bindings = (bindings || SC.EMPTY_ARRAY).slice() ;
    clonedBindings = YES ;
  }

  if (bindings === null) bindings = (base._bindings || SC.EMPTY_ARRAY).slice();
  bindings[bindings.length] = key ;

  // Also add observers, outlets, and properties for functions...
}

From above, look at the second line down. It’s an if-statement that checks if the key has the suffix “Binding” — Eureka! We’ve finally found where all those properties with the word “Binding” get collected to be later processed in the initObservable in SC.Observable.

Now you finally know how we got from the propertyBinding: 'property.path' approach to actually making a binding between two objects’ properties.


That’s All Folks!

There has been a lot to take in to really understand how two central concepts in SproutCore, KVO and bindings, really work. While there are still many more things to know about SproutCore, this will hopefully take a lot of the mystery out of what it really going on behind the scenes.

Oh ya. At the beginning of this post I told you to get a beer. I’m sure by now you’ve probably ended up drinking three or four beers and that means you forgot what you read half way through ;). Sorry.

Have fun!

** (Update: Feb 14, 2010) The observersForKey does not function correctly in SproutCore v1.0. It now throws an type error when provided a key string.

In part 1 of how to make a simple custom view, we focused on the very fundamentals. The three main things we learned were: 1) how to add basic properties to a view that will cause the view to be re-rendered; 2) The need to override the render() method from the base class SC.View; and 3) how to build the HTML in the render method using the passed in context argument that is a SC.RenderContext object. For the second part of how to make a simple custom view, we are going to look at how to instead assign an object to our view and use it to render. If you have completed part 1 of this tutorial you should have all the code ready that we’ll make modifications to.

So let’s pretend that we rather have our user summary view make use of an object in our domain model to display a user’s name, description and age. Therefore, we need to make sure that the model object has three properties, which, as you may have guessed, is a name, description and age property. We’ll create a simple User object that will supply all three properties. Below is a visual of what will be happening:

view_model_assignment

For the purposes of this tutorial, we’ll just be focusing on creating a very simple SproutCore object even though there are more preferred methods of making a model object for a SproutCore application. So with that being said, let’s first create our new user object. Just to get us going, we’ll place the code for our user object in our application’s apps/my_app directory where you should see a core.js file. In the directory create a new file called user.js. Now open up the file and enter the following:


MyApp.User = SC.Object.extend({
	
  name: '',
	
  description: '',
	
  age: ''
	
});

That’s it? That’s it. Notice how how we are extending the SC.Object to create our user object. That way we’ll gain the advantages of SproutCore’s key-value observing (KVO) mechanism.

Okay, great. Now we can go back and focus our attention on our user summary view. From the end of the part 1 tutorial we ended up with our user summary view being the following (see my updates for the changes I made to the view):


MyApp.UserSummaryView = SC.View.extend({

  classNames: ['user-summary-view'],

  name: '',

  description: '',

  age: 0,

  displayProperties: ['name', 'description', 'age'],

  render: function(context, firstTime) {
    var name = this.get('name');
    var description = this.get('description');
    var age = this.get('age');

    context = context.begin('div').addClass('user-summary-view-name').push(name).end();
    context = context.begin('div').addClass('user-summary-view-desc').push(description).end();
    context = context.begin('div').addClass('user-summary-view-age');
    context = context.begin('div').addClass('user-summary-view-age-value').push(age).end();
    context = context.begin('div').addClass('user-summary-view-age-capt').push('age').end();
    context = context.end();

    sc_super();
  }

});

We’re going to play a bit of doctor here and pull some the view’s guts out and and replace it with new parts… Hmm, perhaps I should lay off watching medical surgery shows on TV. Anyway. First things first, let’s strip our view down to the following:


MyApp.UserSummaryView = SC.View.extend({

  classNames: ['user-summary-view'],

  render: function(context, firstTime) {
    var name = '';
    var description = '';
    var age = '';

    context = context.begin('div').addClass('user-summary-view-name').push(name).end();
    context = context.begin('div').addClass('user-summary-view-desc').push(description).end();
    context = context.begin('div').addClass('user-summary-view-age');
    context = context.begin('div').addClass('user-summary-view-age-value').push(age).end();
    context = context.begin('div').addClass('user-summary-view-age-capt').push('age').end();
    context = context.end();

    sc_super();
  }

});

We got rid of the view’s basic properties, the displayProperties property, and render() method is no longer making use of those properties. Awesome. Now what? Now let’s update the view to first be the following:


MyApp.UserSummaryView = SC.View.extend(SC.ContentDisplay, {

  classNames: ['user-summary-view'],

  contentDisplayProperties: 'name description age'.w(),

  render: function(context, firstTime) {
    var name = '';
    var description = '';
    var age = '';

    context = context.begin('div').addClass('user-summary-view-name').push(name).end();
    context = context.begin('div').addClass('user-summary-view-desc').push(description).end();
    context = context.begin('div').addClass('user-summary-view-age');
    context = context.begin('div').addClass('user-summary-view-age-value').push(age).end();
    context = context.begin('div').addClass('user-summary-view-age-capt').push('age').end();
    context = context.end();

    sc_super();
  }

});

Whoa. What’s this content thing’a’ma’bob all about? What we want to do is get our view to observe a given content object. The “content” object can be any type of object. All the view will care about is that it, again, has a name, description and age property. Our view now extends not just our custom logic but also a SC.ContentDisplay mixin. (A mixin is just a set of properties and methods that can be added to any object). The SC.ContentDisplay adds logic to our view that will monitor a content property and detect changes to the content’s properties. The contentDisplayProperties is what we now use to say what content properties we want to trigger a render, which is the content’s name, description and age properties.

(Side note: the w() method is just a convenience to convert a string of words into an array object. The SproutCore framework extended the JavaScript String object to include it among other methods.)

Now that we’ve made the first set of changes to our view, let’s go ahead and modify the render method to make use of the content property. Update the render method to be the following:


render: function(context, firstTime) {
  var name = '';
  var description = '';
  var age = '';
  var content = this.get('content');
  if (content != null)
  {
    name = content.get('name');
    description = content.get('description');
    age = content.get('age');
  }

  context = context.begin('div').addClass('user-summary-view-name').push(name).end();
  context = context.begin('div').addClass('user-summary-view-desc').push(description).end();
  context = context.begin('div').addClass('user-summary-view-age');
  context = context.begin('div').addClass('user-summary-view-age-value').push(age).end();
  context = context.begin('div').addClass('user-summary-view-age-capt').push('age').end();
  context = context.end();

  sc_super();
}

So what did we just do? We simply acquired the view’s content property (added by the SC.ContentDisplay mixin) and got its value for name, description and age using the content’s get() method. Nothin’ to it!

Now that we got all the view’s code it place let’s see what we can do. And like in part 1, we’ll just make use of a browser’s interactive JavaScript console so we can quickly see what is happening. Also remember to start up your application using sc-server. When you start up your browser and direct it to your application you should get the following:

simplecustomview-part2-1

Our view is looking pretty empty but we’ll fix that in a moment. First, let’s create our user object in the console by typing the following:

var user = MyApp.User.create()

Now we have a user object ready to pass to our view. If you look inside the object you’ll see the default value for the object’s properties are empty, that will change but just wait. Okay, now let’s get a reference to our view by typing the following:

var view = MyApp.mainPage.mainPane.userSummaryView

Perfect. All we have to do now is pass our user object to our view by entering the following into the console:

view.set('content', user)

Very simple. Remember how in part 1 we set the properties on the view directly to update the view in the window as in view.set('name', 'Jon Doe')? Well we don’t do that now. Instead we are going to modify the user object to get the view to re-render. Enter the following:

SC.run(function() { user.set('name', 'Luke Skywalker') })

If everything went smoothly you should now see the view updated that displays the name “Luke Skywalker” such as below:

simplecustomview-part2-2

Kick-ass! But why did this just happen? This is where SproutCore’s key-value observing (KVO) comes into play. The view is listening for changes to the content object and when we used the set() method on the user object that triggered the view to react. (We used the SC.run to make sure that the run loop was kicked off to see the changes in the browser immediately). This is pretty cool. Let’s go ahead and now modify the user object’s description and age like so:

SC.run(function() { user.set('description', 'He had daddy issues') })
SC.run(function() { user.set('age', '21?') })

You should see the following:

simplecustomview-part2-3

Excellent! We have successfully updated our view to make use of a content object.

Before we wrap up part 2, I want to just go back to discuss the object being assigned to the view’s content property. Remember that I said the view doesn’t care about the object’s type. The view just cares that the object has the needed properties. So let’s see what that means by assigning a generic SproutCore object to the view’s content property and see what happens. Type the following into your console:

var obj = SC.Object.create({name: 'Darth Vader', description: 'He just needed a hug', age: '60?'})

Good. We just created a generic SproutCore object with properties name, description and age. Now type in the following:

SC.run(function() { view.set('content', obj) })

Again, if everything went fine you should see the following:

simplecustomview-part2-4

This confirms that the view just sees any object given to it as generic. The view just cares about the properties assigned to the object. Now normally in a SproutCore application you would be passing an content object to a view through a controller and make use of bindings, but we used the JavaScript console for quick demonstration purposes.

You have now become a little bit more advanced in creating a custom view in SproutCore. I’ll create future posts about doing more interesting stuff with custom views, but hopefully this and part 1 will get you on the right path. Be sure to check out other excellent blogs here and here to learn interesting SproutCore stuff. The complete code for the custom view is below:


MyApp.UserSummaryView = SC.View.extend(SC.ContentDisplay, {

  classNames: ['user-summary-view'],

  contentDisplayProperties: 'name description age'.w(),
	
  render: function(context, firstTime) {
    var name = '';
    var description = '';
    var age = '';
    var content = this.get('content');
    if (content != null)
    {
      name = content.get('name');
      description = content.get('description');
      age = content.get('age');
    }
	
    context = context.begin('div').addClass('user-summary-view-name').push(name).end();
    context = context.begin('div').addClass('user-summary-view-desc').push(description).end();
    context = context.begin('div').addClass('user-summary-view-age');
    context = context.begin('div').addClass('user-summary-view-age-value').push(age).end();
    context = context.begin('div').addClass('user-summary-view-age-capt').push('age').end();
    context = context.end();
		
    sc_super();
  }

});

[Update (Aug 18, 2009): Be sure to check out my update post that provides some clarification to this tutorial.]

It is very apparent that in order to “get” SproutCore you have to understand a bunch of fundamental concepts, such as how key-value observing (KVO) and bindings work. For someone like myself, I need to work on the fundamentals and have it both verbally and visually explained. For example, one of the most basic concepts seems to be binding a view’s properties with some model object’s properties. Seems trivial enough. However, I kept getting confused how to really connect a view with a model. the examples I would see online always showed something like for view V that has a property called “value” and a model object M that has a property called “value”, you would hook the two together as so:

valueBinding: 'myApp.SomeController.value'

Where the above wiring happens when you create an instance of the view V. I kept asking myself, well what happens if the model object doesn’t have a property named “value”? Then what? What if you want to make a generic view that doesn’t know anything about the properties of some given model? How then to do you bind/wire/hook the two together? Turns out with SproutCore’s bindings the name of the properties doesn’t matter, which is when I got the “a-ha!” moment.

So let’s say I have a view called MyView with two properties, name and description. On the other side, I have two model objects. The first model object is a User object with properties fullname and title. The second model object is a Project object with properties title and description. So to wire the view with the User object we get the following:


nameBinding: 'myApp.userController.fullname'
descriptionBinding: 'myApp.userController.title'

And to bind the view with the Project object we get the following:


nameBinding: 'myApp.projController.title'
descriptionBinding: 'myApp.projController.description'

So based on the above two examples, it becomes clear that the view’s properties and the model’s properties do not have to be called the same thing. Hazzuh! Although if the properties do happen to be called the same thing then that’s fine too. In fact, the example extends to all bindings in general.

Now, the code examples above do raise some other questions. First, you may notice there’s no reference to User object or a Project object. Rather, the bindings seem to be using these controller thingies called “userController” and “projController”. Turns out that it is good practice to not allow views to directly connect to a model object, but, rather, that the view connects to a controller object that acts as a proxy to the model object. The controller decouples the view and the model object. Okay, cool. So you have to create these controller objects. No sweat.

The other thing that may seem weird in the binding examples is the string that looks like some kind of path, such as ‘myApp.userController.fullname’. This is called a property path. SproutCore has this handy feature of looking at an object graph and traversing it to get to a object’s given property. The path can be either relative or absolute. In this case, the example shows an absolute path where the ‘myApp’ object is the root of the graph. Cool. Makes coding easier.

Finally, what’s the deal with the xxxBinding, where the “Binding” is a suffix to the property named “xxx”? When creating a new instance of a view, there is logic that will check for these specially named properties that get added to the view. When found, SproutCore will then auto-magically create the real binding mechanisms that connects the view’s property xxx with the model’s property… er, in this case the controller’s property acting as a proxy to the underlying model.

Anyway, this helped clear up some of the confusion I had. I’ve included a picture to show visually what is going on.

Basic View Binding

Follow

Get every new post delivered to your Inbox.