Working with enumerables

In this section we will look at some useful additions SproutCore provides when working with collections. But first, what do we mean by enumerables? In computing science, enumerables are typically the additions to a collection type that provide useful functions for traversing, searching, filtering, and performing operations on the collection's items. In JavaScript, we have two collection types: Object ({}) and Array ([]). But while the latest version of ECMAScript defines several "enumerable" methods for accessing, manipulating, and iterating over JavaScript arrays, actual support for these methods in the various browser implementations is varied.

As such, one of the convenient extensions that SproutCore provides is the SC.Enumerable mixin. Any object that mixes in SC.Enumerable becomes an "enumerable", which is to say, that the object's contents, ordered or unordered, can be accessed, manipulated, and iterated using a standard interface across all platforms. This means you do not need to worry about a specific JavaScript implementation to use standard methods such as forEach, getEach, setEach, nextObject, and others to work with the objects.

There are actually many helper methods that SC.Enumerable provides, such as map, reduce, and some but we will just look at a couple of the basic methods here and you should refer to the online documentation for more details.

Note

The SC.Enumerable interface is based primarily off of the ECMAScript 5 Array definitions and in cases where the browser provides the function natively, SC.Enumerable will defer to the native version, which will be faster. The difference between the ECMAScript definition and SC.Enumerable is that SC.Enumerable can also be used on unordered collections, and of course using SC.Enumerable ensures that SproutCore apps will still function on the thousands of older browsers out there. Another difference and perhaps the most important one, is that enumerables are Key-value observing (KVO) aware so that changes to the enumerable's content will trigger observers and bindings.

The first thing to know is that while you can create your own enumerable collection classes, SproutCore already includes a few basic ones in the runtime environment: SC.Array ([]), SC.Set, and SC.IndexSet. SC.IndexSet is used for tracking ranges of indexes against large collections and we won't look at it specifically in this book. We will however look briefly at SC.Array and SC.Set right now.

SC.Array

SC.Array is the strangest of the enumerables, in that it's not actually a class but an extension to the SC.Enumerable mixin for ordered collections. In terms of using a plain SC.Array instance, it is actually applied to the native JavaScript array object, which is why I wrote SC.Array ([]) earlier. Therefore to use SC.Array, we just use regular JavaScript arrays. For example:

// Creating SC.Array instances in SproutCore
var x = ['a', 'b', 'c'];
var y = [];

As you can see, there is nothing particularly special about the arrays on the surface. However there are two important points. The first is that we now have access to all of the helper methods of SC.Enumerable and SC.Array. For example, we can use getEach and setEach for simple deep property access as shown in the following screenshot:

SC.Array

The other important point is that we also have access to the KVO-aware methods of SC.Array, which allows us to bind and observe the array attributes and be notified when the array is manipulated. We will look at this in more detail in a moment.

SC.Set

This enumerable-based class is used for unordered collections of items. Similarly to how SC.Array extends the regular JavaScript array, SC.Set can be thought of as an extension over a regular JavaScript object acting as an unordered collection of items. However, SC.Set is not applied to the regular JavaScript object, it is a class and you have to create an instance to use it.

Here is a small introductory example of working with sets. In this example, we create an SC.Set instance and use the SC.Enumerable helper, forEach, to easily iterate through the items.

SC.Set

Observing enumerables

As I've alluded to a couple times already, the main reason for SC.Enumerable and SC.Array is the addition of KVO-aware methods that allow us to be notified when the enumerable's content changes. Let's look at arrays first.

The following KVO-aware methods are added to the regular JavaScript array: pushObject, pushObjects, shiftObject, shiftObjects, removeObject, removeObjects, removeAt, replace, and insertAt. Therefore, if you are mutating an array and you want to ensure that KVO works, you must be sure to use one of these methods.

Here's an example observing the length property of an array for changes. Be sure to pay attention to how the KVC manipulations actually trigger the observer function to run.

Observing enumerables

Notice that the array actually notifies that length has changed when calling replace. This is actually a missing optimization with the implementation of replace in SC.Array that will likely get fixed in the future. Therefore we should not observe the length property to be notified when the contents of the array have changed.

So what should we observe, if it's possible to mutate a collection without changing its length? As it turns out, SC.Enumerable provides a special property [] exactly for this purpose, which we will call the "enumerable" property. By observing the enumerable property, we can be sure to be notified when the contents of the enumerable object change.

Let's look at another example, this time observing the enumerable property [] on an SC.Set instance.

Observing enumerables

As you can see, by observing [] we are properly notified of each change to the contents of the set. Here is the full list of SC.Set's KVO-aware methods: add, addEach, pop, remove, and removeEach.

Observing properties on enumerable items

We already saw that we can observe the [] property of an enumerable to be notified when objects are added and removed from the enumerable, but what about being notified when an individual object's properties change? Have a look at the following example:

Observing properties on enumerable items

In this example, the observer function is never called. This is because while the internal property of the first item changed, it is still the same object as far as the people array is concerned.

To add a deep observer to each item of the array, we use a special property path containing @each. By including @each in the path after an array property, SproutCore will automatically observe the property path on each item in the array. Let's try that example again but with an observer using an @each property path:

Observing properties on enumerable items

As you can see, by using @each.name, our observer function runs when the content membership changes as well as when the name property of any item changes.

Tip

Like with all observers, @each should be used only when necessary as it requires additional processing to set up, run, and tear down.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.191.14.93