Reputation: 2308
I am trying to build a table together with Ember.js and Handlebar.js. Unfortunately I got stuck at the way how to build the cells which consist of Ember.TextArea with valueBinding.
The idea is the following. There is domain model project which has many entries (1 to n relation). Both domain models are different object and are not embedded (the entries are not embedded in the project).
Every project has an array called keys which contains several strings (e.g. 'a', 'b', 'c', ...). Furthermore every entry contains an array of elements. Each of this element has also one of the above mentioned keys as a property key. See the detailed model below.
Models
Project
{ keys: ['a', 'b', 'c'] }
Entries
{
parameters: [
{
key: 'a',
value: 'aaaa'
},
{
key: 'b',
value: null
},
{
key: 'c',
value: '123'
}
]
}
The target is to have in the end a HTML table which contains a column for each key of the project (in the above mentioned case there would be 3 columns with headers 'a', 'b', 'c'). For every entry that is now associated to the project (in other words loaded in the background into an ArrayController), there must be a row. And here comes now the tricky part: Each cell must be bound to the appropriate element of the 'parameters' array (the content of the cell should be an Ember.TextArea).
|| a || b || c ||
-----------------------------------------------------------------------------
| entry 1 binding to element of parameters array where key = 'a' | ... | ... |
----------------------------------------------------------------------------
| entry 2 binding to element of parameters array where key = 'a' | ... | ... |
-----------------------------------------------------------------------------
Approach I
Building the table headers is obviously pretty easy and works of course without any issue:
<table>
<thead>
<tr>
{{#each key in project.keys}}
<th>{{key}}</th>
{{/each}}
</tr>
</thead>
<tbody>
...
<tbody>
</table>
The part where I don't know how to build the code is the body. Iterating over the entries in the array controller possible yes, but how to bind then to the appropriate element - I have no clue. The tricky thing is, that the binding is established to the right element. For example in the column for the key 'a', the binding must be to the element of the parameters array where element.key === 'a'.
<tbody>
{{#each entry in App.entriesController}}
<tr>
{{#each key in project.keys}}
???
{{/each}}
</tr>
{{/each}}
</tbody>
I thought of using a handlebar helper but figured out that Ember.js does (which is different than the documentation of handlebar.js) not pass the object itself, it only passes the name of the property which one can then use to get the value. Unfortunately for an array I do not see how to get the entry of the array that gets currently processed in the each loop.
The idea was to pass the entry and the key to the helper and this one then returns an instance of the Ember.TextArea which is bound to the correct element of the entry.parameters array.
Note: By iterating over the project.keys we can guarantee that the order of the keys is the same as in the header (same iteration order).
Any other ideas how to approach this issue?
Upvotes: 4
Views: 2090
Reputation: 5056
The best solution here is to write a custom handlebars helper. Unfortunately, right now it's not that easy to make your custom bound helpers. There's an old PR here that we'd like to update and get working for 1.0 https://github.com/emberjs/ember.js/pull/615. You might be able to get some ideas from this to do your own implementation.
Upvotes: 4
Reputation: 112
crazy bathtub idea: You could use an Ember.Object as a Proxy, dynamically defining linearized properties on it (in Coffeescript for sanity, names just from braindump):
TheProxy = Ember.Object.extend
fill: (projects, entries) ->
for project in projects
entry = # find entry for project
for key,value of entry
this.set "value_for_#{project.id}_#{key}", value
After that, you could generate the template in a similar fashion, by generating the {{value_for_xxx_yyyy}} bindings and bind a filled instance of TheProxy to it.
Upvotes: 1