How to use an array of strings to refer to a subset of model properties in Ember?

245 Views Asked by At

I'm trying to put a property in my Ember(ember-data) models that is just an array of the properties to include in a generic table component. At first I just added this to my models:

tableColumns: function() {
  return ['age', 'gender', 'whatever'];
}.property()

But now I find myself jumping through hoops in the child components to easily iterate through these these properties and call their values for each model instance.

Since the columns will change with each model I thought this was a good solution. Is there a better way?

I'm getting stuck in particular when for each row(model instance) I want to just say something unreasonable like the below imaginary snippet.

{{#each col in tableColumns}}
  <td>{{model.col}}</td>
{{/each}}

I'm trying to stay controller-free and keep my components generic.

EDIT:

Right now in the row component I'm doing this and then iterating through 'cols' in the hbs. But it doesn't feel right and I'm getting to the async part(some of the columns need to make an external call) that I think will cause some problems so I wanted to find a better way.

this.get('model').tableColumns().forEach(function(cell){
  cols.push(that.get('model._data.' + cell));
});
1

There are 1 best solutions below

1
On BEST ANSWER

You seem to be writing a data table component. I have done this recently, but sadly I cannot share my code with you. I will explain in a general sense how it works:

First, I defined an array of "column" objects. Each column has a "property" attribute, among other things (like a header value, CSS style, etc).

My data-table component tag looks like this:

{{data-table columns=columns content=content rowAction="open" empty-label="Nothing found."}}

In this example, the columns attribute is my array of column definitions and content is an array of records to display.

In the implementation of the component, my template has something like this:

<tbody>
  {{#each row in content}}
  <tr>
    {{#each column in columns}}
    <td>
      <div>{{tablecell row column}}</div>
    </td>
    {{/each}}
  </tr>
  {{else}}
  <tr>
    <td colspan="7"> <em>{{emptyLabel}}</em>
    </td>
  </tr>
  {{/each}}
</tbody>

Finally, I use a custom handlebars component (tablecell):

Ember.Handlebars.helper('tablecell', function(row, column, options) {
  if (!column.property) {
    Ember.warn('You must specify a "property" value for a table column:%@'.fmt(JSON.stringify(column)));
    return '';
  }
  // if it's a function, call passing the row object and return its value.
  if (typeof column.property === 'function') {
    return column.property(row);
  }
  // otherwise, it is a simple property name.  return it from the row object
  return row.get(column.property);
});

You may notice that my tablecell helper can handle property attributes that are strings or functions. This lets me do some custom tweaking of the display value.

I didn't give you the full solution, but hopefully this is enough information to get you on your way!