Reputation: 2847
I've got an Ajax call that's returning a "Team". A team is comprised of a TeamName, LeagueName, and a list of FootballPlayers which have a Name, Position, and TeamName. The Ajax call is correctly returning the Team JSON properly and I'm about to make Knockout bindings to the properties directly on the Team. However, I want to bind a jQuery DataTable to the list of players, but have been unsuccessful in doing so. I can tell the DataTables call is being made, as I can see some of the DataTables controls like "Previous 1 Next" but no data is in the table. I can deploy what I have out to a publicly visible site if that'll be helpful. Thank you!
<table id="playerList">
<thead>
<tr>
<th>Player Name <span class="glyphicon glyphicon-sort-by-alphabet" aria-hidden="true"></span></th>
<th>Position <span class="glyphicon glyphicon-sort-by-alphabet" aria-hidden="true"></span></th>
<th>Team <span class="glyphicon glyphicon-sort-by-alphabet" aria-hidden="true"></span></th>
</tr>
</thead>
<!--<tbody data-bind='foreach: PlayerList'>-->
<tbody>
<tr>
<td data-bind="text: $data.PlayerList.Name"></td>
<td data-bind="text: $data.PlayerList.SelectedPosition"></td>
<td data-bind="text: $data.PlayerList.TeamName"></td>
</tr>
</tbody>
</table>
$('.retrieveTeam').click(function () {
_getData('RetrieveTeam', JSON.stringify({ TeamKey: $(this).data("teamkey") }));
});
function _getData(url, postdata) {
var request = $.ajax({
url: url,
type: 'POST',
data: postdata,
datatype: "json",
contentType: "application/json"
});
request.done(_requestDone);
request.fail(_failedRequest)
}
function _requestDone(result)
{
_bindTeam(result);
my.Views.TeamView.showTeamInfo();
}
function _bindTeam(data) {
if (!viewModel) {
viewModel = ko.mapping.fromJS(data, {}, this);
ko.applyBindings(viewModel);
my.Views.TeamView.applyDataTable('#playerList');
} else {
ko.mapping.fromJS(data, viewModel);
}
}
var applyDataTable = function applyDataTable(element) {
$(element).DataTable(
{
responsive: true,
bFilter: false,
bInfo: false,
bLengthChange: false
});
}
Upvotes: 0
Views: 784
Reputation: 140
Here is how I have done it... this fiddle uses a custom DataTablesForEach binding and also includes a fork of knockout... I have created a pull request with the knockout repository on github. If this solution helps you, please leave a comment on my pull request to get this merged into knockout 3.4.. thanks!
pull request #1856 knockout/knockout repository on github
ko.bindingHandlers.DataTablesForEach = {
init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
var nodes = Array.prototype.slice.call(element.childNodes, 0);
ko.utils.arrayForEach(nodes, function (node) {
if (node && node.nodeType !== 1) {
node.parentNode.removeChild(node);
}
});
return ko.bindingHandlers.foreach.init(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext);
},
update: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
var value = ko.unwrap(valueAccessor()),
key = "DataTablesForEach_Initialized";
var newValue = function () {
return {
data: value.data || value,
beforeRenderAll: function (el, index, data) {
if (ko.utils.domData.get(element, key)) {
$(element).closest('table').DataTable().clear();
$(element).closest('table').DataTable().destroy();
}
},
afterRenderAll: function (el, index, data) {
$(element).closest('table').DataTable(value.options);
}
};
};
ko.bindingHandlers.foreach.update(element, newValue, allBindingsAccessor, viewModel, bindingContext);
//if we have not previously marked this as initialized and there is currently items in the array, then cache on the element that it has been initialized
if (!ko.utils.domData.get(element, key) && (value.data || value.length)) {
ko.utils.domData.set(element, key, true);
}
return { controlsDescendantBindings: true };
}
};
Upvotes: 1