Dhana Krishnasamy
Dhana Krishnasamy

Reputation: 2176

How to use detailTemplate in knockout kendo?

Kendo UI supports detailTemplate to be used, however how to use it via Knockout-kendo bindings?

The jsfiddle code is here

just adding rowTemplate and detailTemplate doesnt work, rowTemplate shows up but when i open open the details i get all sorts of exception (object expected in ASP.NET and jsfiddle breaks)

Upvotes: 2

Views: 1548

Answers (3)

CodeThug
CodeThug

Reputation: 3202

Ideally, this could be fixed by a pull request to kendo-knockout. In lieu of that, you can get knockout data to bind and render properly in a kendo grid detail template by:

First, add the detailTemplate to the list of templates for kendoGrid. To do this, open knockout-kendo.js, search for 'kendoGrid', then add "detailTemplate" to the array of template names. It should look like this after your change:

createBinding({
    name: "kendoGrid",
    defaultOption: DATA,
    watch: {
        data: function(value, options) {
            ko.kendo.setDataSource(this, value, options);
        }
    },
    templates: ["rowTemplate", "altRowTemplate", "detailTemplate"]
});

Second, in addition to having a detailTemplate defined for your binding, add a detailInit binding that binds to a method on your viewmodel. Here is a sample binding:

<div data-bind="kendoGrid: { data: items, detailTemplate: 'myKoTemplate',
    useKOTemplates: true, detailInit: myDetailInit } "> </div>

Third, add the following detailInit method to your viewmodel, so that the binding can find it:

this.myDetailInit = function(e) {
  // Manually fire the databound event on the grid to 
  // get the detail template to unmemoize properly
  e.sender.options.dataBound();
}

Here's a pen with a working example of this: https://codepen.io/codethug/pen/MXoqZy

Still reading? Great. So what's going on here and why is this broken in the first place?

The first part is easy. detailTemplate isn't listed as a template for kendoGrid. Adding that in makes kendo knockout render the template. However, the template gets memoized, but it never gets unmemoized.

Memoization, in this context, means that when kendo asks for the template from the kendo-knockout template renderer, which in turn hands it off to the knockout template renderer, the template is not immediately rendered, but instead, a placeholder in the form of an HTML comment that looks like this: <!--[ko_memo:123abc]--> is inserted in the DOM instead of the rendered template.

Knockout-Kendo makes the assumption that after the templates are rendered, that the dataBound event will be fired on the kendo grid widget. Knockout-kendo hooks into that event to them unmemoize the templates. For usage of templates like the rowTemplate, this assumption is true. When setting up the widget, Kendo calls the render method, then kendo calls the dataBound method.

However, with detailTemplate, the assumption is not true. When you click something to expand details on a kendo grid row, the renderTemplate method is called, but the dataBound event is not fired, presumably because the data didn't change.

We can get around this by manually firing the dataBound event, as seen in the code above. No data has actually changed, but firing that event will trigger kendo knockout into unmemoizing the HTML comment <!--[ko_memo:123abc]--> and replacing it with the properly rendered template.

Upvotes: 0

Dhana Krishnasamy
Dhana Krishnasamy

Reputation: 2176

I followed a different approach where have two rows in row template itself and one row is actual data, the other is detail row. Then use the accordion to trigger the show/hide of detail row. used bootstrap for accordion... works well for me, though its round about way. btw internally this is how they do it as well, but dynamically.

Upvotes: 0

edhedges
edhedges

Reputation: 2718

Here is what I came up with (based on your explanation). I know you have already done a workaround, but here is an answer so this question can at least have an answer in case anyone else runs into this.

View

<div data-bind="kendoGrid: { data: items, columns: columns, pageable: { pageSize: 3 }, scrollable: false, rowTemplate: 'rowTmpl', useKOTemplates: true }"> </div>

<script id="rowTmpl" type="text/html">
    <tr>
        <td data-bind="click: $parent.toggleShowDetails">+</td>
        <td data-bind="text: id"></td>
        <td data-bind="text: name"></td>
    </tr>
    <tr data-bind="visible: showDetails">
        <td colspan="3">
            <div data-bind="kendoGrid: { data: $data.details, scrollable: false }"></div>
        </td>
    </tr>
</script>

ViewModel

var ViewModel = function () {
    var self = this;
    self.columns = [{ field: ' ' }, { field: 'id' }, { field: 'name'}];
    self.items = ko.observableArray([
        { id: "1", name: "apple", details: [{ id: "1", name: "subApple"}], showDetails: ko.observable(false) },
        { id: "2", name: "orange", details: [{ id: "2", name: "subOrange"}], showDetails: ko.observable(false) },
        { id: "3", name: "banana", details: [{ id: "3", name: "subBanana"}], showDetails: ko.observable(false) },
        { id: "4", name: "pineapple", details: [{ id: "4", name: "subPineapple"}], showDetails: ko.observable(false) },
        { id: "5", name: "grape", details: [{ id: "5", name: "subGrape"}], showDetails: ko.observable(false) },
        { id: "6", name: "mango", details: [{ id: "6", name: "subMango"}], showDetails: ko.observable(false) }
    ]);

    self.toggleShowDetails = function (data, event) {
        data.showDetails(!data.showDetails());
    };
};

ko.applyBindings(new ViewModel());

Link to GitHub Issues comment: https://github.com/kendo-labs/knockout-kendo/issues/75#issuecomment-20004008

Upvotes: 1

Related Questions