The Software Simpleton

Nomadic cattle rustler and inventor of the electric lasso

Ember.js - Programmatically Bind From a Handlebars Helper

Warning: The examples use Ember 1.7.1

This is a quick update to my last post where I created a helper that bound data from an external json hash.

One problem I ran into was that if I was not creating links via the link-to helper then the properties were not bound. In line 11 of the gist below, I am returning a simple string that will render the unbound property wrapped in a span tag.

The solution was to call out to the handlebars bind helper after updating the options hash on lines 2-5 below:

Here is an updated jsbin with a full working example.

I am not sure if this is relevant for life after ember 1.7.1 but these techniques have worked well for me thus far.

Ember.js - Rendering Dynamic Content

Warning: The examples use Ember 1.7.1

I’m not going to go into great detail in this post as I think the code examples will be out of date post ember 1.7.1.

I recently had the problem of how to make a complex table reusable accross different datasets. As each dataset would contain objects with different fields, I would not be able to use the usual handlebars syntax of binding:

1
{{property}}

My solution was to create a json hash that is similar to the one in the gist below that specified which fields I was binding to and whether or not, I was going to render a simple text field, a link or for complex scenarios a component:

  • The address structure on line 9 is the most basic as it just specifies a property to bind to.
  • The structure on line 4 contains a route property to signify that I want a link generated.
  • The structure on line 13 contains a component property that unsurprisingly will render a component. A component can also take an array of bindings on line 15 that will have the effect of calling the component like below:
1
{{full-contact name=name address=address}}

Now in my template, I just iterate over this columns collection and either call a handlebars helper that renders the text or link (line 9) or I call out to a different helper that will render the component (line 7)

If I am rendering a simple text or link, then I call the helper that is outlined below:

If I am rendering a component then this helper is called:

Here is a working jsbin.

That is all I have to say on the matter but I would love to hear an alternative or better approach to the above.

Clojurescript - Om - Dynamic Components and Unique Keys

As I get older my tolerance for javascript seems to be getting worse so I’ve been employing clojurescript as a shield from the true horrors of javascript. I’ve been playing around wih om which acts as an interface to facebook’s react.

While developing with om, I kept getting the same javascript error after rendering a dynamic list like below:

If you have done any developing with om, then I am confident in saying that you will have come across this warning after rendering such a list:

Each child in an array should have a unique “key” prop. Check the renderComponent call using <tbody>. See http://fb.me/react-warning-keys for more information.

Here is the code I was using to render such a list:

Line 12 in the above is the villain of this piece as there is no way that I could find of passing a func that will set the key property that react uses to identify each dynamic child.

I have been trying to ignore this warning as it did not cause any code to stop executing but I kept seeing this question pop up on the irc channel and I could not find a good answer on the google.

It also turns out that not supplying a react key for each dynamic item could lead to some very unexpected behaviour.

After consulting the om docs I discovered that om/build can take a third :opts argument and one of the allowed keys is a :react-key which is one of the solutions to the problem.

Armed with this information, I refactored the above code to the following:

The only change is on line 12:

1
(map-indexed #(om/build clip-view %2 {:react-key %1}) clips))

I have used the simplest case of an index for the :react-key but if I was rendering from a list where each item had a unique identifier then I would use the :key option to specify an element property that would be bound as the react key and would look something like this:

1
(map #(om/build clip-view % {:key :id}) clips))

(thanks to Anna Pawlicka) for mentioning this in the comments below.

Or probably the best option of is to pass an :opts map containing a :key option to om/build-all:

1
(om/build-all clip-view clips {:key :id})

Thanks to Daniel Szmulewicz for mentioning this on twitter.

I can now paste a link to this post when somebody asks how to get rid of this warning on the clojurescript irc channel.

Clojure - Lazy Sequences for the Masses

I have recently fallen head over heals in love with clojure and I’ve decided to run through the problems in the excellent 4Clojure site to ensure that I have a good understanding of the language before I even think about dealing with IO or building something meaningful. I’m currently on question 60 which has introduced the concept of lazy sequences and is displayed below:

1
2
3
4
5
Write a function which behaves like reduce, but returns each intermediate value of the
reduction.  Your function must accept either two or three arguments, and the return
sequence must be lazy.

(= (take 5 (__ + (range))) [0 1 3 6 10])

What struck me as totally strange when I first read this problem is that an infinite list is being passed to the function in the form of (range). I had only previously seen range used with at least an end argument like below:

1
2
user=> (range 10)
(0 1 2 3 4 5 6 7 8 9)

But if no start or end arguments are supplied then the default for end is infinity.

1
2
3
;; default value of 'end' is infinity
user=> (range)
(0 1 2 3 4 5 6 7 8 9 10 ... 12770 12771 12772 12773 ... n

So why on earth would you want to supply an ever expanding range? The answer to this puzzle within a puzzle was to clarify what range actually returns which according to the docs is:

Returns a lazy seq of nums from start (inclusive) to end (exclusive), by step, where start defaults to 0, step to 1, and end to infinity.

The 4clojure problem at the start of this post also asks the user to return a lazy sequence for the solution. So what is a lazy sequence? As a newbie to clojure, I struggled to find good information of what an actual lazy sequence was and the docs left me with an unclear understanding of how I should use lazy-seq to construct a lazy sequence.

Lazy Sequences

Laziness in this context means that you can specify a computation that could theoretically take forever to complete, but you can evalutate as much or as little of it as you need. A very simple example of this is below:

1
2
user=> (take 10 (range))
(0 1 2 3 4 5 6 7 8 9)

In the above example, range is being called with no end argument which according to the docs will mean that end defaults to infinity but if we type the expression into the repl, a sequence with the first 10 elements is immediately evaluated so it would appear that take 10 is not waiting for range to reach infinity before grabbing the first 10 elements.

A closer look at what type of sequence is returned starts to give the game away:

1
2
user=> (class (take 10 (range)))
clojure.lang.LazySeq

As range with no end argument defaults to infinity, the only way that this could possibly work is if range returns a lazy sequence or one that realizes its elements as requested. The original 4Clojure problem stated that the sequence returned from the solution must be lazy in order to work with an infinite range:

1
(= (take 5 (__ + (range))) [0 1 3 6 10])

After a quick google to determine how I can return a lazy sequence, I came across the clojure docs for the lazy-seq function but I did not fully grasp what the explanation meant:

Takes a body of expressions that returns an ISeq or nil, and yields
a Seqable object that will invoke the body only the first time seq
is called, and will cache the result and return it on all subsequent
seq calls. See also - realized?

In my haste to complete the problem, I simply thought that all I had to do was wrap an existing function in a lazy-seq call and everything would just magically work. Here is my original attempt at solving the question:

All I have done is wrap a call to reduce on line 3 in a call to lazy-seq on line 2 which of course resulted in a stackoverflow because reduce does not return a lazy sequence and instead will execute until the computation is complete which in this case is never because reduce is being called on an infinite list. I needed to go back to the drawing board. What I needed to do was create a sequence that is realized as needed.

After a bit more digging it became apparent that lazy sequences are not really sequences that simply return a list of elements but are more comparable to iterators in other languages such as java that conform to an a sequence api. With a lazy sequence it is up to the client or the calling function to decide how many elements to consume. A lazy function is just a data structure that waits until you ask it for a value. So how does one return a lazy sequence?

The Simplest Example Imaginable

Below is the simplest example that I could think of:

  • Line 1 defines a function named add-one that accepts a sequence that could be infinite.
  • Line 2 is where the action happens, the lazy-seq macro is employed to create a lazy sequence whose body is an expression. The body of this lazy sequence uses the cons function which takes an element and a sequence and returns a new sequence by prepending the element to the sequence. The element in this case is the result of incrementing the first element of the list with the expression:
1
(inc (first se))

The sequence that the element is prepended to is the result of recursively calling the add-one function again. If a lazy sequence was not returned from add-one then add-one would be called over and over again until a stackoverflow exception was thrown. The whole point of the lazy-seq macro is to circumvent this and ensure that the function will only be accessed as the elements are requested. A sequence that is returned from lazy-seq contains the requested element and a pointer or a function to get the next element.

Another mistake I made in my original misunderstanding was that cons was returning a lazy sequence or was somehow involved in returning a lazy sequence. cons does not return a lazy sequence (the thing that does that is lazy-seq), but it is a good tool to use as part of buidling a lazy sequence.

The 4clojure Solution

Before I show my solution, I will remind you of the original 4Clojure problem.

1
2
3
4
Write a function which behaves like reduce, but returns each intermediate value of the reduction.
Your function must accept either two or three arguments, and the return sequence must be lazy.

(= (take 5 (__ + (range))) [0 1 3 6 10])

The question is really asking the user to recreate clojure’s core reductions function. Below is my solution that took me quite a while to get to but I am very pleased with.

The important things to note are that an infinite range is passed into the named anonymous function my-reduct on line 12 but becase a lazy sequence is returned on line 8 and line 11, the resulting sequence will only be returned as requested. Because the take function is used on line line 1 to request the lazy sequence with an arguement of 5, the function will only be called 5 times.

I found lazy sequences very difficult to wrap my head around and part of that process was to write this post.

If I have inaccuately described anything or I can improve this explanation then please leave a comment below.

ember.js - Animating Deletes With the BufferedProxy

I encountered an interesting scenario in my day job that initially had me scratching my head for a way to solve and seems worthy of a post. The real world application that I am working on actually has real world todos! The application lists the todos as is illustrated in the screenshot below and they can be completed in the time honoured fashion of clicking the checkmark or tick on the left hand side of the todos:


One of the requirements for this list is to display only the todos that have not been completed. Ember does make this ridiculously easy and we could even bind our list to the new filterBy computed property like this:

Here is a working jsbin that shows how easy this is.

The problem with the approach outlined in the jsbin is that, when the checkbox is checked and the bindings are flushed, the view that has been rendered for that particular todo gets instantly destroyed. There are currently no hooks that allow for animations in ember and this is particularly true when it comes to removing items from a bound list or indeed destroying views. This leaves you as the developer to resort to some sort of trickery. I would personally like to see an extra runloop queue or a view lifecycle event that returned a promise. Only when the promise has been resolved would the view’s destroy method be called. There was some discussion about this before ember 1.0 was released but we are heading towards ember 1.6 and I think we need to discuss this again.

My requirements for this todo list are even more convulted because I want to visually indicate that the todo has been checked and also give the user a 4 second chance to change their mind and uncheck the todo before the todo disappears from the list. As you can see from the jsbin, the moment the checkbox is checked, the todo just vanishes instantly. So, what can be done?

The BufferedProxy

The application that I am working on has been in active development for over a year and we still use version 0.14 of ember-data which was the last version of ember-data that was released before the much publicised reboot. I have made a solemn oath to my client that I would not even think of upgrading until ember-data reached 1.0 after the pain we suffered with other ember-data upgrades. One problem with this version of ember-data (I cannot speak for the latest version) is that it is terribly annoying to work with models that are left in isDirty or invalid states. I am not going to go into detail here but the state machine assertions are a source of depression for anybody that has had the experience. I have since patched up my slightly bastardised version of ember-data but what makes life easier is to actually not bind to an ember-data model and only create the model when you are absolutely sure that your model is ready to be persisted.

The BufferedProxy has been an absoute god send for my productivity with this version of ember-data. The BufferedProProxy is a mixin that I mixin into controllers that uses ember’s lesser know method_missing like feature (checkout unknownProperty and setUnknownProperty) to store changes to a controllers model in a buffer that you can either set explicity or you can cancel them completely without the model ever being changed. This is perfect for ember-data models. We can only apply the modifications if we are happy that the model is valid or that the user has not navigated away, cancelled, left the building, been set on fire, shot, kidnapped etc.

The BufferedProxy is ideal for my requirements which are:

  1. I want to delay setting isFinished on the model so that the user has a few seconds to change their mind and undo the change.
  2. I want to animate the deletion of the todo view to make it look a bit more polished than it is in the original bin where it instantly disappears.

Here is a a working jsbin of what I ended up with. There is a delay in persisting the change that gives the user an opportunity to cancel and the delete has a basic animation. If you re-check a todo, then it will not be removed or if you leave it checked, a basic animation will kick in and the todo will be removed when the animation is completed.

The first thing to notice is that I am using render instead of a component to render my todos which gives me a clean separation between controller and view which I think is better for this situation because I want to mix in the BufferedProxy into the controller and not the component even though I am pretty sure it would work with a component:

In the TodoController, I observe the isFinished property for changes in the following handler:

  • On line 4 I am checking if the todo isFinished and the hasBufferedChanges property lets me know that there are changes in the BufferedProxy that are ready to be applied.
  • On line 5, I create an inline function that will be called after a delay. The delay is to give the user the opportunity to change their mind and cancel the change.
  • The inline function on line 5 will raise an event on line 6 to the TodoView that is listening for these events and will give the view the opportunity to animate the delete. The timer is cancelled on line 7.
  • On line 14 we handle the case where the user has changed their mind. We clear the timer and then persist the change if the BufferedProxy has changes.

Below is the TodoView that handles the animateFinish event that is triggered by the TodoController on line 6 of the above gist.

  • line 5 sets up the event handler for animateFinsh events that are raised by the TodoController.
  • lines 10 and 11 uses jQuery’s fadeOut for some basic animation which calls a controller action to persist the changes when the animation has finished.

All that remains is to show the completeFinish action that is called in the above gists:

  • On line 4 of the above gist, I apply the changes from the BufferedProxy by calling the applyBufferedChanges method which will transfer the changes from the buffer to the model.
  • On line 6, I persist the model.

I hope if nothing else that this post has highlighted the complexities of adding animations to ember and especially in the destroy phase. Animation is a must have for modern day javascript single page applications and not a nice to have. I’m not sure if this is on the ember roadmap but I think this is something that can no longer be ignored. I would like to see a run loop queue or view lifecycle event that allowed me to return a promise with the view’s destroy method only being called when that promise has resolved.

Please comment if any of the above has unsettled you.

ember.js - Computed Property for All Keys of an Object

I came across a situation today where I wanted to create a computed property which would recalculate itself every time one of the properties of an object changed. The lazy and tedious thing to do would have been to simply list them out like this:

This is tedious for a number of reasons but the main one is that I have to remember to update the dependent key list, every time the object changes.

Below is the solution I came up with:

This is slightly more convoluted that I would have liked as I could not create a real property because I need the context argument to be an instance on line 3 so that I can call Ember.keys on this instance. Instead of creating an actual property, I use defineProperty on line 11 to create the property at runtime. I create the dependant key list by using Ember.keys to iterate over the subject’s properties and then call Ember.computed.apply to equal the call from the gist at the top of the post.

Below is the calling code:

It is slightly dissatisfying in that I could not create an actual property and if you can suggest a better way then please leave a comment below.

Partial Functions With Bind

I gave a talk last night at the local Glasgow JavaScript user’s group and I was a little surprised that not everybody had heard of the bind method which is a member of the Function.prototype. I put the blame for this firmly at internet explorer’s door because most of us still have to deal with intenet explorer 8 and below which runs ECSMAScript 3 and bind is only available from ECSMAScript 5 and beyond. Internet Explorer has a nuclear half life that is much longer than Chernobyl and will probably still be emitting deadly radiation for many years to come.

The bind method is one solution to having to declare a self or a that or a _this variable when we want to specify what this will be when a function is executed. Below is an example where two new functions (lines 12 and 16) are created in order to set what the context will be when the two variations of the sayHello methods are executed for a particular person:

We can tidy this up by using Function.prototype.bind:

Lines 12 and 13 use bind to create a new function that when called, has its this value set to whatever the given value between the parenthisis is.

It is worth mentioning that if you want to use bind in older browsers then you still can by using a polyfill such as this and I would emplore everybody who is reading this to do just that if you are not already doing so.

Partial Functions

What is less known about bind is that we can use it to make a function with pre-specified initial arguments. These arguments if supplied, follow the provided this value and are inserted at the start of the arguments passed to the target function.

Let me illustrate this with an example, the code below contains a chain of promises with almost identical resolve handlers. I know I could use RSVP.hash for this but I am merely illustrating the point:

On lines 4, 8 and 12 of the above gist, I am setting a property of the self reference to the data returned from the async call and on lines 6, 10 and 14 I am calling getJSON with a different url that will return the next resource. The only things that are different are the property name and the string literal for the next url.

The function below would DRY this up nicely:

The only problem I have is that the above function’s argument list does not fit into my resolve handlers argument list where only one argument is passed containing the result of the async call. The answer is of course to use bind and specify some pre-specified initial arguments:

On lines 9 – 11, I am supplying some pre-specified arguments to the bind function that will be bound to the first two arguments of the continuer function when the specific instances are called. I think this DRYs up things quite nicely.

ES6 Generators - Synchronous Looking Asynchronous Code

In my opinion, the most challenging thing about programming JavaScript in the browser is having to deal with asynchronicity. As developers, we would much rather write code like this:

Our concious mind or left brain operates in what can be thought os as an abstraction of reality. The universe is actually an infinitesimal series of events happening simultaneously at the same time that our concious mind cannot grasp, it thinks sequentially or linearly and we process one thought at a time .We have created our computers to reflect this and for all intensive purposes the programs that we write are at their base level, a series of sequential inputs.

The key to writing good asynchronous code is to make it look synchronous.

The unfortunate thing is that when trying to deal with asynchronicity through the use of plain callbacks, our code has often ended up like the sample below which is often referred to as callback hell:

I could almost live with the code above if it weren’t for error handling. Having to pass callback and errBack handlers to each call quickly turns into a tangled mess.

It is worth stating that there is absolutely nothing wrong with callbacks and they are in fact the currency of asynchronous programming and the newer asynchronous abstractions like promises would not be possible without them. What is wrong with the above code is that it quickly becomes tightly coupled as you pass success callback and failure errorBack callbacks to each asynch call.

Promises are probably the most commonly used alternative to callback hell and below is a refactoring of the above using the RSVP promise library.

What is nice about the above code is that we have one catch handler on line 19 for all of the getJSON calls and in the event of an error in any of these calls, the error will be propagated forward to the next available error handler.

A promise represents the eventual outcome of an asynchronous or synchronous operation. A promise is also referred to as a thenable, which is really just an object or a function that defines a then meethod. A promise is either fulfilled in the good case or rejected in the not so good case. A promise will execute a success callback or an error callback on completion of the asynchronous or even synchronous work. Promises are possibly the most popular solution to callback hell that you will find in production code today. The solution I am going to show with es6 generators makes heavy use of promises to give the illusion of synchronicity.

So if promises are where we are then es6 generators appear to be where we are headed. I’ve just spent the morning playing about with the new generators feature of es6 and I was able to refactor the previous two code samples to the code below, which is almost synchronous looking:

Before I explain what is going on here, let me briefly explain what a geneator is. There are lots of other posts on this article but here is some code that explains how a base level simple generator works:

  • Line 1 Defines a generator function using the new * syntax. A generator function is a function that returns an iterator which can be thought of as an object that moves the target object on to the next value in a sequence. This iterator exposes a next() interface to aid with iteration. A javascript iterator yields successive nextResult objects which contain the yielded value (line 12) and a done flag (line 10) to indicate whether or not all of the values have been returned.

  • Line 11 assigns a returned nextResult object to the local object which we can check on each iteration of the loop. When next is called, the iterator returned from the oneToThree function points to the next yield statement (lines 2- 5) and returns the value. If there are no more yield statements then the done flag is set to true.

It is also possible to send values back to the iterator by calling next with an argument:

In the above example, the return of the yield statement is passed back to the iterator by calling next with the last value that was returned from the iterator and this value is then assigned to the variable on the left hand side of the yield statement. Using this technique, the variables users, contacts and companies on lines 17, 18 and 19 can all be assigned values by passing arguments via next.

If you have grasped this two way communication between the calling code and iterator then you can see that the code above code is not a million miles away from the code below where self.users, self.contacts and self.companies on lines 6, 7 and 8 below are seemingly assigned to the results of asynchronous calls.

The key to this magic is the async function call on line 4 of the above code and below is the listing of this async function.

I lifted the async method from the Q promise library with some minor changes to get it to integrate with promises defined in RSVP that I use on a day to day basis with ember.

Generators work syncnronously which is different than what I originally thought, I thought there was some dark witchcraft that made the calls work asynchronously. This is not true, the key to making them work asynchronously is to return a promise or another object that describes an async task. In this example, each yield statement returns a promise like this:

The basic premise that makes this possible, is that we are passing the generator function to async like this:

The async function assigns the iterator that is returned from this generator function to a local variable on line 16:

The async function then uses the often overlooked ability to pass arguments via the bind function:

The callback and errback function pointers both reference the continuer function on line 2 but because of the way they were declared with the bind function, either next or throw will be bound to the verb parameter depending on which function pointer is invoked.

When the callback reference is invoked on line 20 with the return callback(); statement, the verb argument will have a value of next which will result in the generator asking for the first value from the iterator or generator function.

Which is the equivelant of:

The arg argument will be undefined at this stage because no value has been returned from the iterator. When the first value is asked of the iterator with the above code, the code below will be executed.

The getJSON method returns a promise that is fulfilled or rejected with respect to the successful completion or rejection of the aynchronous ajax call. Once the promise has been created, the yield statement will suspend execution of this function and return the promise created via the getJSON function back to the calling code or async function.

The result variable has been assigned a nextResult object that was described earler that will have a done flag value of false and a value property that will point to the promise created in the iterator.

The code will now encounter this if statment.

As not all of the yield statements have been executed, the done flag will be false and execution will continue after the else statement. The next line calls RSVP.Promise.resolve and passes result.value as an argument which at this stage is still the promise returned from getJSON. RSVP.Promise.resolve in this instance just checks that result.value is a promise and if not, it creates a promise that will become resolved with the passed value. In this instance, result.value is a promise so no Promise cast is required.

This is where things get complicated so keep your wits about you. This result.value promise which was created from the getJSON(‘/users’) call will resolve successfully and result in the callback being executed in the promises’ then method below:

The callback will call the continuer function again:

The callback will call the continuer and bind next to the verb paramter but this time, the arg value will be bound to whatever was returned from the getJSON(‘/users’) asynchronous call. This means that whenever next is called:

The arg value will be returned to the iterator function as was explained in the two way communication section earlier and be assigned to the self.users property that was on the left hand side of the yield statement that called getJSON(‘/users’).

This means that self.users below will now be assigned the result of the async ajax call albeit in a rather round about fashion.

The async function then continues in this recursive manner until all of the yield statements have been called and all of the properties on the left hand side of the yield statements below have been assigned:

Once all the yield statements have been executed, the last nextResult returned from the iterator will point to line 5 of the above code sample and will have the done flag set to true. This means that execution will continue in the if path of the code below and the value of the last nextResult object will be returned to the calling code and the process has completed:

Writing this blog post has completelly demystified what initially seemed like black magic to me. I hope it has done the same for you.

Ember.js - reduceComputed and Property Brace Expansion

Following on from this post I wanted to quickly mention a nice way to perform summary operations on arrays via the reduceComputed computed property.

The docs explain it like this:

Reduce computed properties and computed properties that reduce an enumerable.
Array computed properties are reduce computed properties whose value happens
to be an array.

Reduce computed properties use one-at-a-time semantics to make computations
from arrays pleasant to write without making it easy to introduce O(n²)
runtime for something that only requires O(n).

They can be chained together and retain their O(n) semantics.

I’ve been using ember since 0.9.6 and I have always had a deep fear of the @each observer due to the original implementation whereby the array was recalculated after every change that led to O(n²) problems. I remember having to replace every @each in a project with a binary search equivalent. reduceCompued solves this by only dealing with elements that have actually changed.

Below is an example of something that I have just used for a project that I am working on:

Here is a jsbin that shows a working example.

One other thing of note is that I am using the new property brace expansion syntax on line 2 to reference two values which is a nice short hand sugar to reference two dependant keys in the same key:

1
total: Ember.reduceComputed("deals.@each.{status,value}"

This is known as property brace expansion and is so called because it will expand out to form a new dependant key for each item in the comma delimmited list between the braces.

There are a number of reduceComputed and arrayComputed propeties that come with ember.js out of the box so I decided to cut down on the lines of code in the original implementation by using Ember.computed.filter, Ember.computed.mapBy and Ember.computed.sum to achieve the same result with less code.

In the above gist, I am effectively chaining the results of 3 computed properties together:

  • On line 2 I use Ember.computed.filter to only select the items that I am interested in.
  • On line 5, I map the value I am interested in.
  • On line 6, I then use Ember.computed.sum to reduce the values into one total.

Here is a jsbin with a working example.

I believe there are composable computed properties in the pipeline that will make this code even terser so I look forward to that.

UPDATE: Thanks to hjdivad who I think implemented the arrayComputed features and who pointed out in the comments that I can use the property brace exapansion with Ember.computed.filter.

Emberjs - arrayComputed

I’m not entirely sure when this dropped but I am currently on version 1.3.1 of ember and there is a new computed property macro named unsurprisingly arrayComputed that is especially designed for working with arrays.

The basic premise is that you can observe an array and intercept any additions or removals from the array via some useful hooks that gives the developer the opportunity to further mould the data to their needs.

The docs introduce the feature as this:

Creates a computed property which operates on dependent arrays and
is updated with “one at a time” semantics. When items are added or
removed from the dependent array(s) a reduce computed only operates
on the change instead of re-evaluating the entire array.

One of the problems that this new construct addresses is that when a computed property is declared like below, the entire computed property is recomputed everytime an item is added or removed from the dependency which can be hugely inefficient when dealing with large dependant arrays. The arrayComputed macro uses the now infamous ember.js runloop to coalesce the property changes.

1
2
3
dealTotals: (function(){
  // do something with deals
}).property('deals.[]')

Warning: To take advantage of the one at a time semantics, you need to drop the ‘.[]’ from the dependant key or the property will recomputed everytime the dependency changes. If we take the previous example, the declaration would be:

1
2
3
dealTotals: Ember.arrayComputed('deals' {
  //implementation
});

The best way to illustrate this is with an example, I am going to start with a simple example that works great for a throwaway jsbin or very small amounts of data but is pretty impractical in a real world application. Here is such a working jsbin and here is an arrayComputed definition that will take advantage of the new construct’s hooks to further group the data and provide totals for the grouped data:

  • Line 1 declares a function entry point from which an arrayComputed property will be returned from. It takes a dependent key and a callback which is used to return an object by which the dependent array will be grouped by.
  • Lines 2 – 37 is an object literal definition that defines the members that the Ember.arrayComputed function expects.
  • Line 3 – declares an initial value for the resulting array.
  • Line 4 – is an initialize method that will be called by the framework whenever the computed property is created for real. I am not taking advantage of that in this example but the example at the end of the post does.
  • Lines 6 – 19 provides the addedItem hook that is called every time an item is added to the observed array. This method uses the groupBy callback argument specified in line 1 that when called returns a key to group the array elements by. This rest of the addedItem method simply creates a group if none exists or increments the count if a group already exists. What is worth noting here is that we are not actually adding the item to the array but we are adding the group to the array or updating the group if the array already contains it.
  • Lines 20 – 26 provides the removedItem implementaiton that is really the converse of addedItem.
  • Line 39 actually makes the call to return the arrayComputed property.

Below is how you would use the above computed property:

1
2
3
4
5
App.CompanyItemController = Ember.ObjectController.extend({
  dealTotals: App.computed.groupable('deals',function(deal){
     return deal.get('state'); 
  })
});

You can get quite excited about examples like the one I have just illustrated only to become crestfallen when you apply the above construct to some real asynchronous data. You might be dealing with promises that have not resolved yet or if you are using ember-data then you might call the groupBy callback on an item that is still materializing or has its isLoaded property set to false which means that the groupBy callback will return undefined on most occasions.

Below is a real world example that illustrates an approach of how to get round such problems:

  • On line 3 I am taking advantage of the initialize method to insert some initial values in the resultant array that I can update later.
  • On line 11 I am creating an inline function that does the acutal work of updating the groups that were pushed onto the array in the initialize constructor.
  • On lines 33 – 36 I am checking the isLoaded property of the inserted item and either creating an observer that will postpone the update of the groups until such a time that isLoaded is true or I am calling the function directly.

The arrayComputed construct is a real winner for both of the examples in this post. It is especially useful in the second example because creating an observer in a normal computed property would result in a useless result due to the asynchronous nature of the data but with the new construct, we have a reference to the array which we can update when the data is resolved.

One of the challenges of ember or indeed any single page application architecture is to come up with better abstractions for situations like the second example. I think we need to have less emphasis on examples like the first which make for great demos or jsbins but quickly fall apart when working with real asynchronous data.

My next few posts will be about some of the pitfalls you will face and some solutions when working with real data.