2

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?

Alexander Abakumov
  • 13,617
  • 16
  • 88
  • 129
  • You should probably update the question and turn the code into an actual repro where the final bold part (the actual question?) is the *only* thing not working yet. Otherwise we have to be *guessing* at the missing pieces, making it very hard to give a definitive answer... – Jeroen Sep 28 '15 at 04:32

2 Answers2

2

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.

Roy J
  • 42,522
  • 10
  • 78
  • 102
  • 1
    Thank you! I'll leave this approach as a last resort in case of there is no suitable KO API or technique to achieve what I'm trying to do. – Alexander Abakumov Sep 28 '15 at 15:04
1

You can create your own tr template for foreach binding like

<script type="text/html" id="rowTemplate">

    <tr data-bind="css:{'success': $root.rowClass($data)}, visible: $root.rowFilter($data)">
        <td data-bind="text: name"></td>
    </tr>

</script>

and render it inside your custom binding as

ko.applyBindingsToNode(element, {template:{foreach: data, name: "rowTemplate"}}, bindingContext);
return { controlsDescendantBindings: true };
Dandy
  • 2,177
  • 14
  • 16
  • Thank you! The problem here is that the child layout of the `tr` isn't known prior and is different across the project. I don't know how to address it with this solution. – Alexander Abakumov Sep 28 '15 at 14:58