With ractive.js, you could use javascript to filter the array using a partial and an expression helper function (see http://jsfiddle.net/pUf5P/1/ for full example)
Template:
{{# { index: 0 } }}
{{>lister}}
{{/ }}
<!-- {{>lister}} -->
<ul>
{{# filter(list, .index) }}
<li>{{message}}
{{# { index: id } }}
{{>lister}}
{{/ }}
</li>
{{/ }}
</ul>
<!-- {{/lister}} -->
Setup:
new Ractive({
el: 'body',
template: '#template',
data: {
list: data,
filter: function(list, parent){
return list.filter(function(item){
return item.parentid === parent
})
}
}
})
Or for a pure template solution (see http://jsfiddle.net/pUf5P/2/), you can do:
{{# { index: 0 } }}
{{>lister}}
{{/ }}
<!-- {{>lister}} -->
<ul>
{{#list}}
{{# .parentid === index}}
<li>{{message}}
{{# { index: .id } }}
{{>lister}}
{{/ }}
</li>
{{ /}}
{{/list }}
</ul>
<!-- {{/lister}} -->
UPDATE: I know you wanted to do this "Without looping through the whole array, building a new one", but realize that you are looping through the whole array at each level to find the matching children. You don't need to build a hierarchical structure, just bucket the items based on parent id (see http://jsfiddle.net/pUf5P/3/):
var byParent = {}
data.forEach(function(item){
if(!byParent[item.parentid]){ byParent[item.parentid] = [] }
byParent[item.parentid].push(item)
})
Then use a variant of the above template strategy:
{{# { index: 0 } }}
{{>lister}}
{{/ }}
<!-- {{>lister}} -->
<ul>
{{# { list: byParent[index]} }}
{{#list}}
<li> {{(.message)}}
{{# { index: .id } }}
{{>lister}}
{{/ }}
</li>
{{/list}}
{{/ }}
</ul>
<!-- {{/lister}} -->