walmartlabs/thorax — pull request #38 by syntacticx (2012-05-31 00:41:45+00:00)
Title: 1.3

This version introduces major changes while maintaing backwards compatibility with 1.2. Here are the changes in a nutshell:

1. Specify a template in the view prototype or constructor:

var view = new Thorax.View({
template: '

{{title}}

'
});

This will override the behavior of render(). Calling template() as a function or overriding the template function still works as it normally would. We don't have a use for this in Phoenix, but it makes it much easier to develop without lumbar or rails' asset pipeline, and works great with coffeescript's multiline strings (if that's you're thing (don't tell Kevin it's your thing (it's not my thing, I swear))).

2. view helper now takes an optional block. If you pass a block to it, it will override the template on the passed view (but only in it's use inside of the parent view):

{{#view buttonView}}content for button{{/view}}

This opens up some interesting possibilities for views that have a given set of behaviors but are abstract / don't have a pre-set template.

3. Multi collection binding, this is one of the big ones. One to one model -> view binding makes a lot of sense, but there is no reason that you shouldn't be able to bind multiple collections to a single view (especially in the case of a model having multiple attributes that are collections). I also couldn't find a reason that they should have to be explicitly specified as something needing to be bound at all. In summary:

- the 'collection' attribute no longer has special meaning when passed in the constructor <--- this is the only backwards incompatible change, and it's only incompatible if the view is NOT using the {{collection}} helper, found 3 instances in phoenix and all have been updated in the branch
- collections are automatically bound to the view when using the {{collection}} helper
- the {{collection}} helper now takes a collection as an argument (that defaults to this.collection)
- setCollection is deprecated, use bindCollection if you need to (but you shouldn't need to if you are using the collection helper)

4. collection helper now takes an optional block and a number of optional arguments:

- item-template (a passed block if present will be used as the item-template)
- item-view
- empty-template
- empty-view
- tag (html tag name)
- everything else will be treated as an HTML attribute

Since blocks can be passed the convention of having a separate "name-item.handlebars" template is now entirely optional.

{{#collection items tag="ul"}}

{{itemAttr}}

{{/collection}}

You can mix the block level overrides with an item view as well:

{{#collection item-view="view-name" tag="ul"}}

{{itemAttr}}

{{/collection}}

This will use the block as the template for a new instance of "view-name". Nesting doesn't work yet inline, tried for too long to get this to work and had to move on. The next version perhaps. For now the workaround is just to pass the collection to another view:

Thorax.View.extend({
name: 'Comments',
template: '{{#collection comments}}

{{comment}}

{{/collection}}'
});
var view = new Thorax.View({
template: '{{#empty posts}}empty{{else}}{{#collection posts name="outer"}}

{{title}}

{{view "Comments" comments=comments}}

{{/collection}}{{/empty}}',
model: blogModel
});

This is still a lot easier than before. For reference, the current behavior of the collection helper and the defaults of the new helper would be represented as:

{{collection collection item-template="{{name}}-item" empty-template="{{name}}-empty"}}

5. {{empty}} helper. Takes nothing (checks for a model and model.isPopulated()) or a collection. You can still pass an "empty-view" or "empty-template" to the collection helper, but if you want to do this outside of the collection you can do it like so:

{{#empty someCollection}}
I'm empty
{{else}}
{{collection someCollection}}
{{/empty}}

It's smart enough to re-render when the collection goes from being empty to not empty or back again. I think we should implement something very similar in the loading plugin, such as {{#loading someCollection}}{{/loading}}