2

is there a way to bind elements from inside of custom binding? For example I have custom binding and bind to it observable array of items:

var someArrayOfItems = ko.observableArray(['item1', 'item2', 'item3']);
...
<div data-bind="myBinding: someArrayOfItems"></div>

Now I would like myBinding to list all the elements from 'someArrayOfItems' inside the div element it was bound to like:

<ul data-bind="foreach: someArrayOfItems">
    <li>
        <span data-bind="text: $data"></span>
    </li>
</ul>

Is it possible to make such operation using a custom binding? Thanks for any help.

JotaBe
  • 38,030
  • 8
  • 98
  • 117
Eori
  • 85
  • 2
  • 4

1 Answers1

11

You can use the function ko.applyBindingsToNode to dynamically add a binding to an element.

In your case, you would need to also populate the contents with an appropriate "template".

For example, you could do something like:

ko.bindingHandlers.myBinding = {
    init: function(element, valueAccessor) {
        var ul = document.createElement("ul"),
            data = valueAccessor();

        //append a new ul to our element
        element.appendChild(ul);

        //could use jQuery or DOM APIs to build the "template"
        ul.innerHTML = "<li><span data-bind='text: $data'></span></li>";

        //apply foreach binding to the newly created ul with the data that we passed to the binding
        ko.applyBindingsToNode(ul, { foreach: data });;

        //tell Knockout that we have already handled binding the children of this element
        return { controlsDescendantBindings: true };
    }        
};

Sample here: http://jsfiddle.net/rniemeyer/z458E/

RP Niemeyer
  • 114,592
  • 18
  • 291
  • 211
  • Thanks, this is very helpful. I have one question to this solution. What if I wanted instead of span element to use input element to be able to edit each item in the list. Is it also possible? I tried simply changing span to input, but it isn't working for me. – Eori Oct 28 '12 at 17:05
  • You would need to give it a property name in your data structure. Something like: http://jsfiddle.net/rniemeyer/z458E/2/ – RP Niemeyer Oct 28 '12 at 18:08
  • I have a problem with binding someArrayOfItems length to div. I'm not really sure why is it not working. Could you please check the example http://jsfiddle.net/zbkkzdsp/U49gb/ It is about the line: ko.applyBindingsToNode(div, { text: data().length }). This is bound but when the number of elements changes, this is not revaluated. – Eori Oct 30 '12 at 13:58
  • 1
    When you call `applyBindingsToNode` Knockout receives the result of your code being evaluated (the length of 3). It is not able to track any dependencies and won't get updated again. If you need to make a calculation, then you would need to throw it into a computed. something like: http://jsfiddle.net/rniemeyer/U49gb/1/ – RP Niemeyer Oct 30 '12 at 15:26