2

I'm writing a bindingHandler and want to create a binding-context which has the same parents/parent-contexts like the current bindingContext. Read: no extra binding-context-hierarchy.

Background: I write a dialog-binding-handler
A dom-node has a dialog-binding like data-bind="dialog: { childTemplate: 'childTemplateId' }"
After an click, a generic dialog-template gets rendered and attached to body. You also specify a child-template (= is the desired concrete view), which gets choosen by the generic dialog-template by the binding-context-variable $childTemplateName.
The child-template should have no clue, that there is an extra layer (= generic dialog template) between it and the level containing the dialog-binding-handler. So $parent, $parent.$parent, $parent.$parent.$parent,... are the same in the child-template and the dom-node having data-bind="dialog: ...".

I want to have an extra binding-context so I can extend it with properties specific for this "dialog-call", so the current binding-context doesn't get polluted.

David Rettenbacher
  • 5,088
  • 2
  • 36
  • 45

2 Answers2

1

OK, it seems that
bindingContext.$parentContext.createChildContext(childViewModel);
works perfecly!
So using $parentContext is the (acutally logical) way to go.

(if I remember correctly I had tried this previously with no success with pervious versions of knockout...but nevermind)

David Rettenbacher
  • 5,088
  • 2
  • 36
  • 45
0

bindingContext.extend returns a new bindingContext:

ko.bindingHandlers.dialog = {
    init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
        var innerBindingContext = bindingContext.extend({
            dialogProperty1: ...
        });
        ko.applyBindingsToDescendants(innerBindingContext, element);

        return { controlsDescendantBindings: true };
    }
};

so this should do what you are trying to achieve: a new bindingContext with the same hierarchy and dialog-specific extensions that does not pollute the context outside of your dialog binding.

janfoeh
  • 10,243
  • 2
  • 31
  • 56
  • I can't use `{controlsDescendantBindings: true }` because the dom-node containing `data-bind: "dialog: ..."` can have contents which have their own bindings... So if I use it an "bound twice" error is thrown. However, I found a working solution. But thanks for your efforts! – David Rettenbacher Feb 03 '15 at 14:39
  • It should be the other way around? `controlsDescendantBindings: true` _prevents_ bindings from being bound twice. – janfoeh Feb 03 '15 at 14:42
  • Yes, but my code executes the template on the `click`-event - much later. So actually the children of the dialog-calling-node (bad name, I know) *must* be bound by knockout. – David Rettenbacher Feb 03 '15 at 14:45
  • Gotcha - I missed the part where you used a template, and thought that the child nodes of 'dialog' where the content. I solved this problem pretty much the same way then. [Here's my binding](https://github.com/janfoeh/veiljs/blob/master/veil-knockout.js) in case you're interested. – janfoeh Feb 03 '15 at 14:57
  • Hey thanks, maybe I have a closer look at it. @code: you pass your viewmodel directly instead of creating a bindingContext - is that intentional? Because you lose your parents this way (if I recall my tests correctly). `ko.renderTemplate(veilTemplate, bindingContext.$parentContext.createChildContext(valueAccessor()), {}, overlay.get(0))` would help keeping the parents ;) – David Rettenbacher Feb 03 '15 at 15:09
  • The binding is meant to be called with the desired bindingContext as the valueAccessor, such as `veil: $data`. I often found the need to use one of the call sites' parent contexts, and this makes it easier. – janfoeh Feb 03 '15 at 15:15