Search code examples
javascriptknockout.jscustom-binding

Custom binding(?) that adds some standard Knockout bindings to child nodes


I want to implement using Knockout something easily reusable (probably, custom binding) that could apply mix of standard bindings: the foreach binding to a tbody node and another standard bindings (visible and css) to its tr child nodes.

AFAIK, the best way it can be achieved is to write a custom binding.
I want to use it like that:

<table>
    <tbody data-bind="tableRows: { rows: unfilteredItems, filter: rowFilter }">
        <tr data-bind="possibly, some hard coded bindings including visible and css bindings">...</tr>
    </tbody>
</table>

, where unfilteredItems and rowFilter are some observables.

I want the custom binding to 'transform' this into the following and let KO process this as it was initially in the layout:

<table>
    <tbody data-bind="foreach: unfilteredItems">
        <tr data-bind="visible: rowFilter($data), css: rowClass($data), and now hard coded bindings, if any">...</tr>
    </tbody>
</table>

Here rowClass() is a function contained in the component and just returns a string that should be appended to the tr's class attribute based on the current $data.

I know how to apply the foreach binding to the node that my binding is applied to:

ko.bindingHandlers.tableRows = {
    init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
        var options = valueAccessor(),
            rows = options.rows;

        ko.applyBindingsToNode(element, { foreach: rows }, bindingContext);
    }
};

This part is working perfectly.

But I can't find anywhere how to add bindings to the child tr nodes, so that when the foreach binding would process child nodes, that bindings (and all bindings that already contained in the child layout) were applied to and processed in the same manner as they were initially in the layout.

I could try to manually add the required bindings to the child tr nodes as a string in the init function using JS DOM API, but I have feeling that it should be cleaner solution using some KO API.

Also, I need the custom binding to properly handle cases when there initially are another bindings on the tr nodes including both visible and css bindings.

My project uses Knockout 2.2.1 and it would be nice if the solution doesn't rely on the Knockout 3 features, if possible.

Could someone suggest how to achieve this?


Solution

  • I think you should be able to modify the data-bind attributes of the inner elements of the foreach using jQuery's data or similar. The outer would be processed by Knockout before its inner parts would. I haven't tried such things myself.

    In fact, since you're just doing boilerplate-rewrite, you could use jQuery to find and rewrite the tags before you apply Knockout bindings at all. That would save you the custom binding handler.