Clean table construction and DOM-manipulating directives

38 views
Skip to first unread message

Bartholomew Furrow

unread,
May 13, 2015, 8:50:10 PM5/13/15
to ang...@googlegroups.com
I'd like to use Angular directives to automatically build nice tables for me, and I'm having trouble.

I have a bunch of JS objects like this one:
{product: 'ProdA',
 colour: 'Black',
 team: 'U16B',
 count: 5}.

Here's what I want the table to look like:

Team | Product | Count
----------------------
U14B | ProdA   | 20
     |---------+------
     | ProdB   | 20
     |---------+------
     | ProdC   | 20
-----+---------+------
U14G | ProdA   | 19   
     |---------+------
     | ProdD   | 19   
...

Notice that "colour" wasn't in the table, and was aggregated over.

The problem is that I have at least four tables like this, and I'm thinking it would be worth my time to make a clean solution. I'm looking for a clean way of doing this, and I'm hoping Angular Directives can help. Here's an example of how I imagine it could work:

<table class="item_table"
  sort-rows
  aggregate-identical-rows-in-rightmost-column
  make-rowspans-for-identical-cells
  make-alternating-rows-different-colours>
<tr>
  <th>Team</th>
  <th>Product</th>
  <th>Count</th>
</tr>
<tr ng-repeat="row in all_data_rows">
  <td>row.team</td>
  <td>row.product</td>
  <td>row.count</td>
</tr>
</table>

The problem is that when any of the directives in the <table> tag run, the rows created by the <tr ng-repeat...> don't exist yet. From this mailing list I see that I could go to the innermost ng-repeat and call a directive that checks for $last at every level, but this seems sketchy and is a really weird place to put those directives.

Am I trying to use directives for things they aren't designed for? Is $last really a perfectly good solution, even if I have nested ng-repeats and I have to check for $last all the way out to the <table> tag? Does anyone have a good way of doing this angularly?

I know there are javascript approaches I could take, but once the contents of the cells get more complicated (e.g. buttons), those get messier. This solution just seems so pretty if it would only work. I'd appreciate any thoughts.

Thanks,
Bartholomew

Luke Kende

unread,
May 14, 2015, 2:34:32 AM5/14/15
to ang...@googlegroups.com
First of all, I'd work on one directive concept at a time and then build up to complexity as appropriate. Your ng-repeat does not have to be outside the directive but can be in the directive's template, and instead pass in the data to the table's directive.  You can then have custom directives in them template of your custom directives.

<table special-table="all_data_rows" group-by="{{colour}}"></table>

//this is quick typed to show idea not to be accurate javascript
.directive('specialTable', function(){
   return {
     scope: {
       rows: '=specialTable',
       groupBy: '@'
     },
     template: '<thead><tr><th ng-repeat="header in headers">{{header}}</th></tr></thead><tbody><tr ng-repeat="(group, row) in rows"><td ng-repeat="(key, value) in row" ng-attr-rowspan="{{row.count}}">{{value}}</td></tr></tbody>',
     link: function(scope, element, attrs) {
       
       //using underscore.js to simplify data manipulation
       scope.headers = _.keys(scope.rows[0]);
      
       //group items by colour or whatever you passed in
       var grouped = _.groupBy(scope.rows, scope.groupBy);
       
     }
   }
})

This is not a finished example, but just giving you the approach I would take to see if that gets you thinking.

Bartholomew Furrow

unread,
May 14, 2015, 6:30:23 PM5/14/15
to ang...@googlegroups.com
Luke,

Thanks so much for the response. It looks like the core of your idea is to build the table in the directive. I had a similar approach where I basically built the table entries in a JavaScript array of arrays, then had a simple <tr ng-repeat><td ng-repeat>... sort of thing to display it. If one of the entries had HTML elements in it, they wouldn't render, which I gather is a very reasonable security precaution; but it looks like this approach circumvents that nicely.

Thanks for unsticking me!
Bartholomew

--
You received this message because you are subscribed to a topic in the Google Groups "AngularJS" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/angular/-DuD9KH-sq8/unsubscribe.
To unsubscribe from this group and all its topics, send an email to angular+u...@googlegroups.com.
To post to this group, send email to ang...@googlegroups.com.
Visit this group at http://groups.google.com/group/angular.
For more options, visit https://groups.google.com/d/optout.

Luke Kende

unread,
May 15, 2015, 4:10:42 PM5/15/15
to ang...@googlegroups.com
Yes, your template for a directive can have another directive and you are on the right path to create your data structures such that iterating over them "lines-up" with angular's ng-repeat in the goal you are looking for.  Glad you are seeing a path.

Luke
Reply all
Reply to author
Forward
0 new messages