Framework: Nested repeats

Created on 24 Feb 2015  路  10Comments  路  Source: aurelia/framework

Can inner repeat access values of outer repeat and how exactly ? Here is an example I am experimenting with:

this.tabHeader = [{width: 50, name: 'col 1'}, {width: 100, name: 'col 2'}];
this.tabData = [[1, 2], [3, 4]];
<table>
  <thead>
    <tr>
      <th repeat.for="header of tabHeader">${header.name}</th>
    </tr>
  </thead>
  <tbody>
    <tr repeat.for = "line of tabData">
      <td repeat.for="field of line">${field} - ${tabHeader[$index].name</td>
    </tr>
  </tbody>
</table>

In a td element or attribute I need to access the tabHeader value but no luck with constructs tried so far. If I loop over tabHeader in tbody, can't access the line array element:

<tr repeat.for = "line of tabData">
  <td repeat.for="header of tabHeader">${line[$index]} - ${header.name}</td>
</tr>

Shall this work and how, without replicating header data on each line ?

question

Most helpful comment

<table>
  <thead>
    <tr>
      <th repeat.for="header of tabHeader">${header.name}</th>
    </tr>
  </thead>
  <tbody>
    <tr repeat.for = "line of tabData">
      <td repeat.for="field of line">${field} - ${$parent.$parent.tabHeader[$index].name</td>
    </tr>
  </tbody>
</table>

You are two levels in, so you will need to jump up two levels and then access tabHeader. It's not ideal, but it should work. I'm doing nested repeaters in my work just fine.

All 10 comments

Have you tried accessing the outer variables with $parent?

no success that way either.

Right now I don't see that there is anything available _currently_. If you inspect the template tag that is in the DOM you can find a primaryBehavior property that contains the executionContext which shows you what is currently available. It doesn't appear that the object is set properly yet but I am still checking in to it. If this is not yet currently available I think I have a way we can add this but I need to check with Rob first.

<table>
  <thead>
    <tr>
      <th repeat.for="header of tabHeader">${header.name}</th>
    </tr>
  </thead>
  <tbody>
    <tr repeat.for = "line of tabData">
      <td repeat.for="field of line">${field} - ${$parent.$parent.tabHeader[$index].name</td>
    </tr>
  </tbody>
</table>

You are two levels in, so you will need to jump up two levels and then access tabHeader. It's not ideal, but it should work. I'm doing nested repeaters in my work just fine.

Many thanks. The use case is rendering a bigger table. Table rows (line of tabData) contain only data values. Metadata like column tooltip, width etc. are only in tabHeader and help rendering data cells nicer, is the reason for accessing them. The proposed solution approach is fine for me.

We would like to make this nicer in a future version, but it's working this way for now.

sure, the elegance comes later :-)

the with-binding might could help here so you don't have to repeat $parent.$parent over and over again. https://github.com/aurelia/templating-resources/blob/master/src/with.js

just to document on more finding, uncritical for experimenting, perhaps interesting for analysis. two table elements below are identical, except $parent.$parent used in 2nd one, to adjust the width.
When the model changes both tables rendered identically (except cell width). If the model changes to recordsFound = 0 and Records=[], the view does not change at all (both tables displayed with previous model state). If the model changes again, to non zero records, all works fine. If the 2nd table below commented (with $parent.$parent), zero case works for the 1st table. In short, for the view below, the method with $parent.$parent works for non-zero case, in a test.

<div class="bodycontainer scrollable">
  <table id="resultTableBody" class="table table-hover table-striped table-condensed table-bordered">
    <tbody>
    <tr repeat.for="record of Records" click.delegate="$parent.rowSelect($index, $event)">
      <td repeat.for="field of record">${field}</td>
    </tr>
    </tbody>
  </table>
</div>


<div class="bodycontainer scrollable" >
  <table id="resultTableBody" class="table table-hover table-striped table-condensed table-bordered">
    <tbody>
    <tr repeat.for="record of Records" click.delegate="$parent.rowSelect($index, $event)">
      <td repeat.for="field of record" width="${$parent.$parent.Headers[$index][4]}">${field}</td>
    </tr>
    </tbody>
  </table>
</div>

I know that this has been closed for awhile but I stumbled across this while looking for a solution. I found a better way of doing this using the <let> element. Posting here to help anyone else who is looking for a better way:

<template>
  <let $root.bind="$this"></let>
  <table>
    <thead>
      <tr>
        <th repeat.for="header of tabHeader">${header.name}</th>
      </tr>
    </thead>
    <tbody>
      <tr repeat.for = "line of tabData">
        <td repeat.for="field of line">${field} - ${$root.tabHeader[$index].name</td>
      </tr>
    </tbody>
  </table>
</template>
Was this page helpful?
0 / 5 - 0 ratings

Related issues

arnonuem picture arnonuem  路  5Comments

ghost picture ghost  路  4Comments

pvettori picture pvettori  路  3Comments

danfma picture danfma  路  5Comments

jfbaquerocelis picture jfbaquerocelis  路  3Comments