The Software Simpleton

Nomadic cattle rustler and inventor of the electric lasso

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.

Emberjs - Custom Link-to Refactor

In a previous post, I blogged about creating a custom link-to helper that takes any ember-data model and creates a link to that model. I had it all working nicely in this jsbin which uses the fixture adapter to simulate pulling data from an external service. I was feeling quite smug after writing this post but I soon got shot down in flames when I plugged the helper into a real appliation that is pulling data from a true asynchronous service. The picture below illustrates that not all of the sidebar items have a link to signify who the email is from:

I was horrified but it soon be came clear that the devil was at play or to put it another way, asynchronicity was at play. Below is a refresh of my custom link-to helper that I will use to discuss the problem:

The if statemnt Line 6 of the above branches the code execution by deciding whether or not the helper is declared in its block or non-block formats. The helper in this troublesome example is declared in its non-block format like this:

1
{{resource-link-to contact}}

As the helper is decared in its non-block format, options.fn will be undefined and so the code execution will continue onto lines 7 – 11. The problem stems from how I was getting the anchor label text on line 11. On line 3, I get a reference to the ember data model and on line 11 I was trying to access a generic property named displayName that I know exists on each of the ember data models in this project. This is problematic when pulling the data from a real external service because the ember data model might not have been loaded or materialized when the helper is trying to access this property as you can see in the image of the console below:

The solution

The solution involves gaining a better understanding of the the options hash that is passed into each handlebars helper. The code below from the custom helper sets the options.types array and the options.contexts for each string argument that will be passed to the real link-to helper:

1
2
3
4
5
6
7
if (!options.fn)  {
  options.types = ['STRING', 'STRING', 'ID'];
  options.contexts = [this, this, this];
  args.unshift(name);
  args.unshift(resourceRoute);
  args.unshift(resource.get('displayName'));
}else{

The args variable will look like this when we are finished:

1
[undefined, "contact", "contact", Object]

The first argument is undefined for reasons explained above, but each of the first 3 arguments above will marry to the options.types array which currently looks like this:

1
options.types = ['STRING', 'STRING', 'ID'];

A type of ‘STRING’ means it is a string literal and will just be displayed as is but if the type is ‘ID’ then this denotes that it is a property path and it should be accessed from the context at same array index of the options.contexts array.

Armed with this knowledge, the answer was to make displayName an ‘ID’ type that is a property path to the context. The updated code looks like this:

On line 2 of the above gist, I change the first element of the array from STRING to ID and on line 6 I push the property name onto the args array that will be passed to the real link-to helper.

The only thing left to explain is how the displayName property gets rendered into the inner html of the anchor tag that link-to helpers produces when the ember-data model is materialized and its isLoaded property is true. The LinkView class that the real link-to helper creates does this in the code below:

On line 3 of the above gist, a linkTextPath variable is assigned to the helperParameters.options.linkTextPath property that will point to the displayName property we created in the custom link-to helper. This linkTextPath value would be undefined if the option type was still ‘STRING’.

Here is a jsbin of the end result.

I was annoyed when my helper did not initially work but as is often the case, it has led me to a greater understanding of the internals of a framework which is very important.

One last note is to point out that this is a great example of why the fixture adapter is not a good simulation of asynchronicity. It is still very useful but you never run into the occassion where the models have an isLoaded set to false because they are loaded straight from the FIXTURES array. Don’t go too deep with the fixture adapter on a real project, you will end up in a fairy tale world that is very different from reality. I am speaking from heavy experience on this point.

Emberjs - Creating a Timeago Helper

Freetime is very hard to come by when you have two small children under three but I actually had a couple of hours spare at this time of writing and had set myself the challenge of implementing an ember.js timeago handlebars helper when I came across this example by @jgwhite that does exactly that. The README gives a very good breakdown of how to implement the helper.

I’ve made some slight changes which you can see in this working jsbin. My view is pretty much the same apart from that I am comparing raw javascript dates instead of using moment.js.

The key to making this work is the notifyPropertyChange method which is a convenience method that calls propertyWillChange and propertyDidChange. Calling both these methods consecutively is actually what happens behind the scenes when you call set() on an object and the combination triggers a notification to all registered obervers that the property has changed.

My handlebars helper is ever so slightly different and possibly worth a brief comment and is listed below:

Line 4 adds a new property to the the hash property of the options argument. Handlebars will mix any property in this options hash into the view. You can also set up bindings and other goodness for each property that you add by using the option.hashTypes hash. I am not doing that in this instance but it is worth noting that you can.

Line 6 uses the view helper to insert a new instance of the App.TimeAgoView into the output. It is worth noting that this is the helper that is called by handelbars for normal view declarations like this:

1
{{view App.SomeView}}

The upshot of all this is that I feel a bit deflated as I was really looking forward to sinking my teeth into this. I guess I have @jgwhite to thank for that.

I now need a new chanllenge…….and something that I have actually written to blog about…..

Ember.js - Creating a Custom #link-to Handlebars Helper

Following on from my last post about how to create a custom if helper, I now want to show how to create a custom link-to helper.

Ember’s routing is arguably the best feature of ember. Recently while using amazon’s S3 file storage web interface where the tree like structure of buckets or folders is implemented client side, I was frustrated to find that the url does not change as you navigate from bucket to bucket which means that you cannot link to a specific bucket or if you refresh the page or naviagate away and then come back you are back at the root bucket. With ember, you have the ability to make every location on your site linkable thanks to ember’s excellent routing and the {{link-to}} helper is a nice convenience that takes a resource and returns a url to that resource.

The Problem

While iterating over a list of similar model types, you can simply use the link-to helper to create links to each item in the list but what if the list contains two or more different types as is illustrated in the gist below where the route’s model hook returns a combination of user and contact types.

One approach would be to do something like this:

The isUser condition could compare the context’s constructor but this approach is limited as every time you want to link to a different type, need to update the template. I actually started down this unmaintainable path before souring on the idea as is illustrated in this jsbin.

As in my previous posts, the answer to the problem was to create a wrapper around the link-to helper and perform a bit of massaging with the arguments array before passing them on to the real link-to helper.

Another consideration is that I want to be able to call my custom helper in both the block form and the non-block form. It is possible to call the link-to helper in its non-block form like this:

1
{{link-to 'Link Label' 'users' model}}

The end result is that I want to be able to create the same handlebars expression anywhere in the application and have the helper create the correct link for me. I want to do this:

1
{{resource-link-to this}}

or this:

1
2
3
{{#resource-link-to this}}
  {{fullName}}
{{/resource-link-to}}

And the correct link will be rendered without any thought from me

The Solution

Here is a jsbin of my finished resource-link-to helper.

First of all I wanted to create an easy way of getting the corresponding route path from a DS.Model type. I want to be able to get the corresponding route from the type. If for example, I have an App.Employee type then I want to be able to get the string route to that resource which is employee. Below is a humanize method which does exactly that and is mixed into all DS.Model types:

Below is my resource-link-to helper that I finally ended up with after much coffee and profanity. The premise is that I am simply creating a new argument list to pass to the link-to helper.

  • On line 3. I am pulling the resource from the context via the name parameter that is defined in the argument list on line 1.
  • On line 4 I am using the humanize extension function to get the name of the route.
  • Line 6 contains an if expression where we branch depending on whether the resource-link-to helper is called in its block or non-block formats.
  • options.fn will be present if we create the helper in the block form and options.fn is the function that will be called to create the text between the blocks. If the helper is called in its non-block format then we need to pass an extra argument to the real link-to helper and on line 11 we get the new argument from a common property that appears on every model in my example but you could use any logic you like here.
  • On lines 7 and 13 and lines 8 and 14, we are passing contextual information for each argument that will be passed to the real link-to helper. If you consider that we would be calling the link-to helper like this:
1
{{link-to 'Label Text' 'contact'  model}}

Then we set the option types and contexts for each argument like this:

1
2
options.types = ['STRING', 'STRING', 'ID'];
options.contexts = [this, this, this];
  • If one of the argument types equates to ‘ID’ then it is considered to be a a property of the context at the same array index as that of the options.contexts array while ‘STRING’ means the argument is treated as a literal.
  • On line 18 I am simply calling the real link-to helper with the newly created argument list.

And that is that. Now we have this wrapper, we can use whatever logic we want to get our route names and link text.

If you have anything to say then please leave a comment below.

Ember.js - Creating a Custom Handlebars if Helper

This is post is really a continuation of a post that I wrote some time ago about how to call a handlebars helper from another handlebars helper.

I came across a situation today that cried out for me to create my own version of the handlebars if helper. The if helper is one of the first handlebars helpers that you will experience and one you will use time and time again along with its inverse, the unless helper.

The if helper can be used in a hanldebars template like so:

1
2
3
4
5
{{#if isTrue}}
  {{!do stuff}}
{{else}}
  {{! don't do stuff}}
{{/if}}

The above code will test the property expression of the current context for a truthy value and if one is found it will execute the code between the if and the else or the closing if, if no alternative else was provided. If the current context in the above code was a controller called IndexController then it would check the isTrue value of that controller:

1
2
3
4
5
App.IndexController = Ember.ObjectController.extend({
  isTrue: (function(){
      return true;
  }).property()
})

The if helper is also a live helper and handlebars creates an observer for whatever property expression you pass to it which means that any changes to the property will cause that part of the template to re-render. This is one of the things that first drew me to ember.

One of Handlebars strengths is that it is logicless, which means you cannot use things like the logical && operator to combine property expressions like this:

1
2
3
{{#if isTrue && alsoTrue}}
  {{!do stuff}}
{{/if}}

You could put together an ugly hack that creates multiple if calls like below but I really did not want to go down that path.

1
2
3
4
5
{{#if isTrue}}
  {{#if alsoTrue}}
    {{!do stuff}}
  {{/if}}
{{/if}}

My scenario concerned only displaying ember-data models that did not have their isNew, isDeleted or isLoading flags set.

The naieve and crude approach would have been to do this:

1
2
3
4
5
6
7
{{#unless isNew}}
  {{#unless isDeleted}}
    {{#unless isLoading}}
      {{!do stuff}}
    {{/unless}}
  {{/unless}}
{{/unless}}

Instead I created my own custom if helper that is really just a wrapper around the handlebars boundIf helper that adds a property to the context and then calls the real boundIf helper.

Below is how the newly christened ifIsLive helper that is called from the handlebars template:

1
2
3
{{#ifIsLive model}}
  {{!do stuff}}
{{/ifIsLive}}

All I am doing is passing in a property path to the model object from the context.

And here is the implementation:

  • On line 2, I retrieve the model from the context.
  • On line 5, I check to see if the custom property exists on the context.
  • If the property does not exist then I create the computed property using ember’s slant on the EMAScript 5 defineProperty which takes an array of dependant keys to create a computed property from.
  • Lastly, I call Ember.Handlebars.helpers.boundIf, using the JavaScript call method to maintain the context and I also pass in the newly created isLive property from which the framework will create an observer to watch for changes.

The boundIf does all the clever stuff and is really the hero of the piece but I think this is a useful technique to DRY up your code.

Ember.js Components, Wrapping Content and Context

I have created this ember.js component that allows a user to hook up a data source that can be filtered via user input and then added to a destination:

You have most likely used something similar when you have been adding tags to some sort of entity.

The component is declared using the hyphonated convention like this:

1
{{auto-suggest source=controller destination=tags}}

This all works great but what if I wanted give users of the component the ability to add their own content to the results?

An example of this might be if you wanted to use the component to add mail recipients to an email form and you wanted to add an avatar to each possible suggestion and selection:

It turns out that you can also declare components in a block form whereby components can be passed a handlebars teamplate that is rendered inside the component’s template whenever a {{yield}} expression appears.

I wrongly assumed that if I added the appropriate {{yield}} statements to my component template then it would be possible for the user to specify their own content like this AND the component’s context would be mainatined.

All that appeared to be left was to add the{{yield}} statements to my existing template which I did on lines 4 and 15 of the following gist:

And now we get to the meat of the post, the above approach will work fine if you are adding static content to each item but in my case I wanted to bind the appropriate avatar to the src attribute of the img tag and the appropriate text to the alt attribute. On closer inspection, this was not happening.

It is worth remembering that both my {{yield}} statements are declare in an {{each}} helper:

If I log what the context is in the component’s block, I can see it is the context of the parent view and not of the component:

After a cry for help, I received some sage advice from marciojunior_me, that it is possible to override the _yield method of the Ember.Component to this:

Lines 14 and 15 are the important lines of the above gist where we keep the context of to the current view and not the parentView.

With this in place, all is good again:

It is worth noting that the _yield method is prefixed with the underscore which denotes a private method that you override at your own peril but I have good test coverage in order to catch any future breaks.

I do think this raises an important point about what the context should be when the {{yield}} helper is executed. I personally think it makes more sense like this as it make sense in this context but I think you could argue either way.

If you have anything to say on the matter please leave a comment below.