Facing a challenge porting Angular 1.x to Aurelia 1

For quite a while (in between other projects) I’ve been working on porting an Angular 1.x SPA to Aurelia 1. Almost all of the porting have gone well but one dialog has recently stopped me dead in my tracks. In said Angular application this dialog contains a table with a fixed header and then multiple <tbody> elements (see below). AFAIK these elements get marked with class ng-scope (by Angular?)

<tbody on-finish-render="" ng-repeat="row in model.viewModal.table | searchFilter:searchModel" class="ng-scope">

From what little I know about Angular when each tbody element is marked with ng-scope the element gets its own “view-model” so to speak and thereby handle any state changes “locally”, i.e. within the “scope”. Now from what I understand about Aurelia is that Aurelia’s view-model “maps” to Angular’s scope (or the other way round). If correct this has led me to assume that I need to wrap each <tbody> element in a custom element since adding repeat.for to a tbody doesn’t seem to work. This sort of produces the result I want but it messes up the layout. So I’m stuck and not being able to deliver this functionality to my customer makes me feel quite like an idiot right now.

Caveat: I’m not an Angular developer and I’ve been a long time away from Aurelia.

Complete Angular mark-up:

<table class="editabletable">
	<thead>
		<tr>
			<th style="width: 47px;">
				<div style="min-width: 36px;min-height: 36px; height: inherit; width: inherit;">
					<input id="headerCheckBox" checked type="checkbox"
						   ng-click="selectAll($event, model.viewModal.table, searchModel)"
						   ng-checked="areAllSelected(model.viewModal.table, searchModel)"
						   ng-disabled="isAnySelectable(model.viewModal.table, searchModel)"/>
				</div>
			</th>
			<th>
				<div class="modalheader" ng-bind="model.viewModal.columnNames[0]"></div>
			</th>
			<th>
				<div class="modalheader" ng-bind="model.viewModal.columnNames[1]"></div>
			</th>
			<th>
				<div class="modalheader" ng-bind="model.viewModal.columnNames[2]"></div>
			</th>
			<th>
				<div class="modalheader" ng-bind="model.viewModal.columnNames[3]"></div>
			</th>
		</tr>
	</thead>
	<tbody on-finish-render ng-repeat="row in model.viewModal.table | searchFilter:searchModel">
		<tr class="parentrow" ng-class="{lockedRow:!row.isSelectable}" ng-init="showExpanded=true;isChecked(row)" ng-show="(displayAll || row.isSelectable)">
			<td style="width: 30px; height: inherit; width: inherit;">
				<span ng-if="!row.isSelectable">
					 <img src="../../img/chain_16px.png" title="{{getText('no.selectable.elements')}}">
				</span>
				<span ng-if="row.isSelectable">
				  <input id="{{'cmpTemp' + row.Code}}" type="checkbox" ng-click="selectAllBelongingToParent($event, row)" ng-checked="row.isSelected"/>
				</span>
			</td>
			<td>
				<a ng-hide="showExpanded" style="width: 300px" ng-click="showExpanded=!showExpanded"><img src="../../img/arrow-right.png" alt=""></a>
				<a ng-show="showExpanded" style="width: 300px" ng-click="showExpanded=!showExpanded"><img src="../../img/arrow-down.png" alt=""></a>
				<span>{{row.Name}} (<b>{{row.numberOfChildrenSelected}}</b>/<b>{{row.totalNumberOfChildren}}</b>)</span>
			</td>
			<td style="min-width: 150px"></td>
			<td style="min-width: 150px"></td>
			<td style="min-width: 150px"></td>
		</tr>
		<tr id="{{'rowElement' + $index}}" ng-repeat="info in row.childMap" 
			ng-class="{childSelectedColour:info.isSelected,lockedRow:!info.isSelectable}" 
			ng-show="showExpanded && (displayAll || info.isSelectable)"
		>
			<td style="min-width: 36px;min-height: 36px;">
				<span ng-if="info.isSelectable">
					<input id="{{'chldTemp' + $index + row.Code}}" type="checkbox" ng-click="childClicked($event, info, row)" ng-checked="info.isSelected"/>
				</span>
				<span ng-if="!info.isSelectable">
					<span ng-if="info.assignedOther !== null">
						<img src="../../img/chain_16px.png" title="{{info.reasonNotSelectable}}">
					</span>
					<span ng-if="info.assignedOther === null">
						<img src="../../img/clock-2_16px.png" title="{{info.reasonNotSelectable}}">
					</span>
				</span>
			</td>
			<td name="xname" style="min-width: 150px">
				<span style="padding-left: 14px">{{row.Name}}</span>
			</td>
			<td>{{info.Name}}</td>
			<td ng-bind="info.otherAssigned"></td>
			<td ng-bind="info.lastAssignedOther"></td>
		</tr>
	</tbody>
</table>

Most of the mark-up above is easily ported to Aurelia and this is my first attempt at solving the repeating :

<template repeat.for="item of tableData | filter:filterInput.value">
  <table-body item.bind="item" showall.bind="showAll" index.bind="$index"></table-body>
</template>

where table-body is the custom element containing the <tbody> mark-up. However, as mentioned above, this messes up the lay-out.

Is what I’m trying to do achievable in Aurelia? If yes, any pointers?

I haven’t read this properly, but whenever I see custom element, tables and formatting my first go to is: have you looked into containerless?

No, I haven’t but will do.

What can I say other than Aurelia FTW! and thank you @jwx!!!

containerless did the trick. Wow!

The only remaining (small) problem now is that when I scroll down the rows bleed through the fixed header.