I have created a fiddle for my scenario:
I am using a template binding at the end where I bind the SelectedListItem() observable to the data property of the template binding.
I am faking an async ajax call with the setTimeout of 4 seconds. Then I fill the observables and the SelectedListItem with an alarm item.
But this is 4 seconds too late because before happens a binding error with alarmNumber which is bound in the template.
I would need a ko with: SelectedListItem() bind for the template but I have never seen it.
Furthermore I could use ko comment binding like
<!-- ko with: SelectedListItem() -->
<!-- template binding here... -->
<!-- /ko -->
because then I would have to set the currentChildTemplate() observable in every AlarmViewModel what makes no sense at all.
How can I solve that?
HTML
<div id="rightHeader" style="float: right; background: green; height: 100%; width: 10%;">
</div>
<div style="clear: both;"></div>
</div>
<div style="float: right; background-color: seagreen;"></div>
</div>
<!-- /ko -->
<script id="map" type="text/html">
<div style="position: absolute; top: 200px; background-color: green; width: 300px; height: 200px;" data-bind="text: alarmNumber"></div>
</script>
<script id="response" type="text/html">
<div style="position: absolute; top: 200px; background-color: red; width: 300px; height: 200px;" data-bind="text: alarmNumber"></div>
</script>
<div data-bind="template: { name: currentChildTemplate(), data: $root.SelectedListItem() }"></div>
CSS
body, html {
width: 100%;
height: 100%;
padding: 0;
margin: 0;
}
.alarmTemplate {
height: 80px;
margin: 10px;
background: lightgray;
border: black solid 1px;
padding-left: 5px;
}
#alarmListContainer {
height: 80px;
background: yellow;
vertical-align: middle;
background: gray;
border: black solid 1px;
display: table;
width: 100%;
margin: 0 auto;
}
#navigationWheeler {
background: yellow;
display: table-cell;
vertical-align: middle;
}
.selected {
background-color: #0094ff;
}
#toggleButtonLeft {
border: black solid 1px;
cursor: pointer;
text-align: center;
width: 40px;
}
#toggleButtonRight {
width: 40px;
border: black solid 1px;
cursor: pointer;
text-align: center;
}
* {
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
.cellContainer {
width: 20%;
float: left;
}
JAVASCRIPT
function AlarmWheelViewModel(alarms) {
var self = this;
self.SelectedListItem = ko.observable();
self.selectListAlarm = function (alarm) {
self.SelectedListItem(alarm);
}
var alarms = [];
for (var i = 0; i < 10; i++) {
var alarmVM = new AlarmViewModel(i, 'test' + i, 'yeahh', self.SelectedListItem);
alarms.push(alarmVM);
}
self.currentChildTemplate = ko.observable('response');
self.visibleAlarms = ko.observableArray(); // Display only the first 5 alarms
self.hiddenAlarms = ko.observableArray(); // Hide the remaining alarms
// faking async ajax call here to test how the UI behaves when the SelectedListItem is not set yet
// the result is that alarmNumber can not be bound just as I have expected :/
setTimeout(getData, 4000);
function getData() {
self.visibleAlarms(alarms.slice(0, 5)); // Display only the first 5 alarms
self.hiddenAlarms(alarms.slice(5)); // Hide the remaining alarms
self.SelectedListItem(self.visibleAlarms()[1]);
};
self.hideCurrentAlarm = function () {
$('#currentAlarm').hide();
}
self.hideAlarmList = function () {
$('#currentAlarm').show();
};
}
function AlarmViewModel(alarmNumber, alarmMessage, alarmAddress, selected) {
var that = this;
that.alarmNumber = alarmNumber;
that.alarmMessage = alarmMessage;
that.alarmAddress = alarmAddress;
that.isSelected = ko.computed(function () {
return selected() === that;
});
}
var vm = new AlarmWheelViewModel();
ko.applyBindings(vm);