Let me setup the question with a simple case.
I have an HTML table, the rows of which are controlled by an observableArray. It works great.
If the observable
The Knockout-Repeat binding applies the binding to the element itself. It does so by using a node preprocessor to wrap elements with the repeat
binding in virtual (comment-based) elements at run time.
var vm = {
contacts: ko.observableArray()
};
ko.applyBindings(vm);
setTimeout(function() {
vm.contacts(['One', 'Two', 'Three']);
}, 2500);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.3.0/knockout-min.js"></script>
<script src="https://rawgit.com/mbest/knockout-repeat/master/knockout-repeat.js"></script>
<table>
<tbody data-bind="repeat: !contacts().length && 1">
<tr>
<td>There are no contacts specified yet.</td>
</tr>
</tbody>
<tbody data-bind="repeat: contacts().length && 1" data-repeat-bind="foreach: contacts">
<tr>
<td data-bind="text:$data"></td>
</tr>
</tbody>
</table>
Like you, my first choice would be virtual tags for an if
binding. But since that's not an option, how about swappable templates?
var vm = {
contacts: ko.observableArray()
};
ko.applyBindings(vm);
setTimeout(function() {
vm.contacts(['One', 'Two', 'Three']);
}, 2500);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<template id="empty-body">
<tbody>
<tr>
<td>There are no contacts specified yet.</td>
</tr>
</tbody>
</template>
<template id="normal-body">
<tbody data-bind="foreach: contacts">
<tr>
<td data-bind="text:$data"></td>
</tr>
</tbody>
</template>
<table data-bind="template: contacts().length === 0 ? 'empty-body' : 'normal-body'"></table>