This jquery mobile table is being rendered with knockout.
<table data-role="table" id="report-table" class="ui-body-a ui-shadow ui-responsive table-stripe"
data-column-btn-theme="a" data-column-btn-text="Spalten..." data-column-popup-theme="a" data-mode="columntoggle"">
<thead>
<tr data-bind="foreach: columns">
<th data-bind="text: $data.Caption, attr: { 'data-priority': 1 + Math.floor($index() / 4) }"></th>
</tr>
</thead>
<tbody data-bind="foreach: { data: rows, afterRender: tableRowAfterRender }">
<tr data-bind="foreach: $parent.columns">
<!-- ko template: { name: $data.template } -->
<!-- /ko -->
</tr>
</tbody>
</table>
To get the "columntoggle" to actually work, I currently use the "aferRender" event:
self.tableRowAfterRender = function (element, data) {
// Skip unless data.Items()[i] is not the last element in the rows collections
for (var i = 0; i < data.Items().length - 1; i++) {
if (data.Items()[i] !== self.rows()[self.rows().length - 1].Items()[i])
return;
}
// refresh table after 100ms delay
setTimeout(function () { $("#report-table").table("refresh"); }, 100);
}
This is shaky, I hate the setTimeout() way of doing things, and this situation became quiet common for me with jquery mobile and knockout. I need a robust way to raise an event once all the knockout rendering or ideally once all the rendering concerned with elements inside the table-element is done. I was able to use custom bindings in some such situations, but I would not know how to do this here.
Try this. Wrap the table with: <div data-bind='template: { afterRender: myPostProcessingLogic }'>.
Then do whatever you need to do in myPostProsssingLogic. This will only be called when the table is first rendered however. Here's a fiddle:
<div data-bind='template: { afterRender: myPostProcessingLogic }'>
<table data-role="table" id="report-table" class="ui-body-a ui-shadow ui-responsive table-stripe"
data-column-btn-theme="a" data-column-btn-text="Spalten..." data-column-popup-theme="a" data-mode="columntoggle"">
<thead>
<tr data-bind="foreach: columns">
<th data-bind="text: $data.Caption, attr: { 'data-priority': 1 + Math.floor($index() / 4) }"></th>
</tr>
</thead>
<tbody data-bind="foreach: { data: rows, afterRender: tableRowAfterRender }">
<tr data-bind="foreach: $parent.columns">
<!-- ko template: { name: $data.template } -->
<!-- /ko -->
</tr>
</tbody>
</table>
You can try to use binding init
ko.bindingHandlers.init = {
init: function(element, valueAccessor, allBindings, viewModel) {
var action = valueAccessor();
if (typeof action === 'function') {
setTimeout(action.bind(viewModel, element), 0);
}
}
};
Like this:
ko.components.register('simple-component', {
viewModel: function(params) {
this.title = params.title;
this.initHandler = function() {
console.log('DOM of component has been built.');
};
},
template:
'<div data-bind="init: initHandler">\
Title is: <span data-bind="text: title"></span>\
</div>'
});
Information for more complex cases is here - http://blog.atott.ru/2015/08/dom-built-event-for-knockout-components.html
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With