Can ng:repeat add multiple child elements for each item?

5,588 views
Skip to first unread message

werehamster

unread,
May 19, 2011, 8:45:18 PM5/19/11
to angular
Firstly: my apologies if this is the wrong place to post this, if so
please point me in the right direction and I'll post it there.

My question is this: I want to repeat a number of rows in a table but
each item needs to add 2 rows to the table not just one. The code
should explain:

Using knockout I'd do something like:

<table>
{{foreach item in items}}
<tr><td>{{item.name}}</td><td>{{item.value}}</td></tr>
<tr><td colspan = "2">{{item.description}}</td></tr>
{{endforeach}}
</table>

But in angular I'm stuck because ng:repeat is an attribute widget, not
a directive. The best I can do is:

<table>
<tr ng:repeat="item in items">
<td>
<table>
<tr><td>{{item.name}}</td><td>{{item.value}}</td></tr>
<tr><td colspan = "2">{{item.description}}</td></tr>
</table>
</td>
</tr>
</table>

Which, as you can see, pretty much sucks.

Why don't you use <div>s instead?

I know that that's a possible solution, but I'm dealing with tabular
data (bank account transaction history) and the rows need to line up.
I'm pretty certain that I can work around it if I need to but I was
hoping that I'd just missed something obvious.
There's also the possibility of putting each double row in it's own
tbody section (eg <tbody ng:repeat="item in items"> but the real
question I want answered is the first one. Can ng:repeat add multiple
child elements for each item?

Thanks in advance,
Karl




Igor Minar

unread,
May 20, 2011, 5:19:31 PM5/20/11
to ang...@googlegroups.com
Hi there,

This is unfortunately a limitation of HTML and DOM. Angular has DOM
based templates, meaning that a DOM tree is a template for the view.
Knockout uses string based templates which in all cases but this one
are an inferior choice.

The main issue with tables is not the lack of some kind <ng:repeat>
widget, but rather that you can't add foreign elmenets into the table
dom. If you do that, browser will strip them. tables and select html
elements are special in this way.

we are thinking about some solution to work around this issue, but
currently have nothing to offer except for restructuring your DOM so
that you have only one root element that needs to be iterated over.

/i

> --
> You received this message because you are subscribed to the Google Groups "angular" group.
> To post to this group, send email to ang...@googlegroups.com.
> To unsubscribe from this group, send email to angular+u...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/angular?hl=en.
>
>

karl

unread,
May 21, 2011, 2:22:20 AM5/21/11
to angular
Thanks Igor,
I suspected as much.

For now the multiple <tbody> elements appears to work in all the
required browsers (IE6+) for me so I'll have to stick with that for
now. Tempted to try building my own widget to fix it, but I suspect
that may no be doable due to browsers "fixing" my invalid html.

<table>
<my:foreach expr="item in items">
<tr><td>{{item.name}}</td></tr>
<tr><td>{{item.value}}</td></tr>
</my:foreach>
</table>

but I'm guessing you've already tried this approach.
I suspect that you'd need to fallback to using special html comments
if you we're looking for an approach that would work on all elements
(tables, selects, etc...).

Thanks for the definitive answer,
much appreciated.

Karl

Witold Szczerba

unread,
May 21, 2011, 1:49:14 PM5/21/11
to ang...@googlegroups.com
I was thinking about some possible solution. The markup would look like this:

<tr ng:repeat="{linked} f in foo">
<td ng:bind="f.firstName"></td><td ng:bind="f.lastName"></td>
</tr>
<tr linked>
<td ng:bind="f.currentDept"></td><td ng:bind="f.dueDate"></td>
</tr>

The ng:repeat widget could check if the {attributeName} exist and then
merge the template with another DOM nodes, so that would result in:
<tr>
<td>Jason</td><td>Forester</td>
<td>1234</td><td>22/05/2011</td>
</tr>
in one repeat cycle. It does, however, look awkward a little, doesn't it?

Regards,
Witold Szczerba

Igor Minar

unread,
May 21, 2011, 1:53:28 PM5/21/11
to ang...@googlegroups.com
yeah the following doesn't work:

<table>
 <my:foreach expr="item in items">
   <tr><td>{{item.name}}</td></tr>
   <tr><td>{{item.value}}</td></tr>
 </my:foreach>
</table>

because when the browser parses the html, we end up with DOM looking like:

<table>
<tbody>


   <tr><td>{{item.name}}</td></tr>
   <tr><td>{{item.value}}</td></tr>

</tbody>
</table>

notice that the my:foreach tag was stripped by the browser.

The ideas we have is to use directives as markers:

<table>
   <tr ng:repeat="item in items"

ng:repeat-sequence-start><td>{{item.name}}</td></tr>
   <tr ng:repeat-sequence-end><td>{{item.value}}</td></tr>
</table>

Or now I thought of another approach that uses comments to relay
instructions to angular:

<table>
<tbody>
<!--  ng:repeat expr="item in items" -->


   <tr><td>{{item.name}}</td></tr>
    <tr><td>{{item.value}}</td></tr>

<!--  ng:repeat -->
</tbody>
</table>

Note that I had to add tbody tags explicitly because otherwise the
first comment ended up outside of the tbody that is automatically
added by browsers and the other one was inside.

We need a bit more testing and exploration before we decide on the
final solution.

/i

Igor Minar

unread,
May 21, 2011, 1:55:59 PM5/21/11
to ang...@googlegroups.com
this is similar to the first proposal I just posted, but allows the
repeated sequences to be named which will likely need to be supported
if we want to support nesting with this kind of repeaters.

/i

Witold Szczerba

unread,
May 21, 2011, 3:42:40 PM5/21/11
to ang...@googlegroups.com
Yes, the "linked" was an identifier, so there can be multiple links
between different repeat sections. In fact, I think there is nothing
to prevent using the ng:repeat sections to link separated nodes, so
that would be possible (but maybe useless) to build two or more tables
(or whatever else) in one loop cycle, like this:
<table>
<tr ng:repeat="{baaar} f in foo">......</tr>
</table>
<table>
<tr baaar>.....</tr>
//or maybe more readable:
<tr ng:repeat-master="baaar">.....</tr>
</table>

werehamster

unread,
May 21, 2011, 5:45:54 PM5/21/11
to angular
How about a slightly different approach? Using ng:repeat-children,
which would repeat the child nodes of a given element?

<table>
<tbody ng:repeat-children="item in items">
<tr><td>{{item.name}}</td></tr>
<tr><td>{{item.value}}</td></tr>
</tbody>
</table>

This isn't quite as flexible as the "linked" sections above, but IMO
it's far more readable and easier to understand. Also not as flexible
as the comment based approach, however as @Igor pointed out using
comments can have unexpected results (ie; the comment is moved outside
of the table by the browser).





On May 22, 7:42 am, Witold Szczerba <pljosh.m...@gmail.com> wrote:
> Yes, the "linked" was an identifier, so there can be multiple links
> between different repeat sections. In fact, I think there is nothing
> to prevent using the ng:repeat sections to link separated nodes, so
> that would be possible (but maybe useless) to build two or more tables
> (or whatever else) in one loop cycle, like this:
> <table>
>  <tr ng:repeat="{baaar} f in foo">......</tr>
> </table>
> <table>
>  <tr baaar>.....</tr>
>  //or maybe more readable:
>  <tr ng:repeat-master="baaar">.....</tr>
> </table>
>
> On 21 May 2011 19:55, Igor Minar <iimi...@gmail.com> wrote:
>
>
>
>
>
>
>
> > this is similar to the first proposal I just posted, but allows the
> > repeated sequences to be named which will likely need to be supported
> > if we want to support nesting with this kind of repeaters.
>
> > /i
>
> > On Sat, May 21, 2011 at 10:49 AM, Witold Szczerba <pljosh.m...@gmail.com> wrote:
> >> I was thinking about some possible solution. The markup would look like this:
>
> >> <tr ng:repeat="{linked} f in foo">
> >>  <td ng:bind="f.firstName"></td><td ng:bind="f.lastName"></td>
> >> </tr>
> >> <tr linked>
> >>  <td ng:bind="f.currentDept"></td><td ng:bind="f.dueDate"></td>
> >> </tr>
>
> >> The ng:repeat widget could check if the {attributeName} exist and then
> >> merge the template with another DOM nodes, so that would result in:
> >> <tr>
> >>  <td>Jason</td><td>Forester</td>
> >>  <td>1234</td><td>22/05/2011</td>
> >> </tr>
> >> in one repeat cycle. It does, however, look awkward a little, doesn't it?
>
> >> Regards,
> >> Witold Szczerba
>
> >> On 20 May 2011 23:19, Igor Minar <iimi...@gmail.com> wrote:
> >>> Hi there,
>
> >>> This is unfortunately a limitation of HTML and DOM. Angular has DOM
> >>> based templates, meaning that a DOM tree is a template for the view.
> >>> Knockout uses string based templates which in all cases but this one
> >>> are an inferior choice.
>
> >>> The main issue with tables is not the lack of some kind <ng:repeat>
> >>> widget, but rather that you can't add foreign elmenets into the table
> >>> dom. If you do that, browser will strip them. tables and select html
> >>> elements are special in this way.
>
> >>> we are thinking about some solution to work around this issue, but
> >>> currently have nothing to offer except for restructuring your DOM so
> >>> that you have only one root element that needs to be iterated over.
>
> >>> /i
>
> >>>> For more options, visit this group athttp://groups.google.com/group/angular?hl=en.
>
> >>> --
> >>> You received this message because you are subscribed to the Google Groups "angular" group.
> >>> To post to this group, send email to ang...@googlegroups.com.
> >>> To unsubscribe from this group, send email to angular+u...@googlegroups.com.
> >>> For more options, visit this group athttp://groups.google.com/group/angular?hl=en.
>
> >> --
> >> You received this message because you are subscribed to the Google Groups "angular" group.
> >> To post to this group, send email to ang...@googlegroups.com.
> >> To unsubscribe from this group, send email to angular+u...@googlegroups.com.
> >> For more options, visit this group athttp://groups.google.com/group/angular?hl=en.

Igor Minar

unread,
May 22, 2011, 12:25:49 AM5/22/11
to ang...@googlegroups.com
The issue with this approach is that you can't have "fixed" children.
Let's say you want the last row of the table to be a row of sums, but
since you a repeating over all children, you'll repeat the sum row
with every iteration too.

/i

Karl

unread,
May 22, 2011, 2:17:37 AM5/22/11
to ang...@googlegroups.com
> The issue with this approach is that you can't have "fixed" children.

Good point, I hadn't considered that, and it's a reasonably common user
case as well. In theory the "fixed" rows could be put into a separate
<tfoot> but that's not really addressing the problem.

Petter

unread,
May 23, 2011, 3:58:50 AM5/23/11
to angular
I would very much like to not use comments to dictate behavior. I
changes the meaning of a comment. It would be much harder to read the
code and understand what it does, especially if you are new to
angular.

Just my two cents,
/Petter

Igor Minar

unread,
May 23, 2011, 2:46:09 PM5/23/11
to ang...@googlegroups.com
I agree. especially given the unintuitive browser DOM construction behavior.

as I said, this is not an easy problem to solve and make everybody happy. :-)

Rosina Bignall

unread,
Nov 29, 2012, 4:03:34 PM11/29/12
to ang...@googlegroups.com
Has any further developments occurred on this front?  


I need to create a table like this:

<tr>
<td> something</td>

<span ng-repeat="item in items">

<td>{{item.name}}</td>
<td>{{item.desc}}</td>

</span>

</tr>

As mentioned before this won't work because the "invalid" span tag will be ignored by the browser.  

I have used the tbody solution a number of times for multiple trs and it is a good solution, but unfortunately there is no containing element for <td>s.  Has anyone found a solution to this problem?
Reply all
Reply to author
Forward
0 new messages