1

I'm having a problem with a custom knockout binding handler that creates a context. The demonstration is here: http://jsfiddle.net/gf3tfarz/14/

When 'container' is applied to an observable array, it's not updating the children elements.

<div data-bind="container: { data: selectedCountry().ids }">
    <p>Error: <span data-bind="text: $container.data().length"></span></p>
    <div data-bind="foreach: $container.data">
        <p>Error: <span data-bind="text: $data"></span></p>
    </div>
</div>

This is the custom binding handler:

ko.bindingHandlers.container = {
    init: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
        var innerBindingContext = bindingContext.extend({
            $container: ko.utils.unwrapObservable(valueAccessor())
        });

        ko.applyBindingsToDescendants(innerBindingContext, element);

        return { controlsDescendantBindings: true };
    }
};

I'd like a way that both examples using 'container' present in the demonstration work.

Note that using "with" it works.

  • 3
    Sorry, _what_ is wrong with the fiddle? What are we looking at? How do we know it is not working? You know, what is expected? What is actually happening? It seems functional to me. – Jeff Mercado Nov 21 '14 at 19:29
  • All the texts after "Error:" does not update when the select is changed. That's the error. In my opinion, it should change like all the texts after "Ok:", which uses different techniques. – Adriano dos Santos Fernandes Nov 22 '14 at 02:05
  • 1
    One more or less easy solution would be to turn your $container into a computed: http://jsfiddle.net/wn5zp9qu/. However in this case you have to write `$container()` every where you want to use it: `data-bind="foreach: $container().data"` – nemesv Nov 22 '14 at 14:03
  • That's good @nemesv. I was looking into something similar, but was unable to construct it myself. Just now need to see if it works in my real code, which is much more complex than this test. – Adriano dos Santos Fernandes Nov 22 '14 at 17:24
  • you can also use ko.contextFor(element) – segFault Nov 24 '14 at 19:25
  • @segFault in what way it would benefit in my demo code? – Adriano dos Santos Fernandes Nov 25 '14 at 16:21

1 Answers1

0

You shouldnt be extending the bindingContext directly, you should create a child binding context. Then it will work how you expect it to.

ko.bindingHandlers.container = {
    init: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {       
        // Make a modified binding context, with a extra properties, and apply it to descendant elements
        var innerBindingContext = bindingContext.createChildContext(
            bindingContext.$rawData, 
            null, // Optionally, pass a string here as an alias for the data item in descendant contexts
            function(context) {
                ko.utils.extend(context, {
                    $container: ko.utils.unwrapObservable(valueAccessor())
                });
            });

        ko.applyBindingsToDescendants(innerBindingContext, element);

        return { controlsDescendantBindings: true };
    }
};

See the bottom of this page for more info... http://knockoutjs.com/documentation/custom-bindings-controlling-descendant-bindings.html

Dean North
  • 3,741
  • 2
  • 29
  • 30