Dirk Boer
Dirk Boer

Reputation: 9065

Knockout.js - How to create a custom bindingHandler similar to 'with'

I'd like to make a custom bindingHandler, something like data-bind="withSmartForm: formModel".

But despite all the other functionality I want it to behave like with, so the current context changes to formModel, and I can access the subproperties like data-bind="value: email".

I know there are workarounds like always prefixing the subproperties with formModel, or put a with: formModel in a parent element, but as I will be using this pattern a lot I'd like to keep it as short as possible.

In the following fiddle I'd like to merge the with and withSmartForm into one bindingHandler.

http://jsfiddle.net/k89Fg/1/

Any ideas? Thanks!

Update: working example

http://jsfiddle.net/k89Fg/4/ - thanks to Andrew Walters for the winning answer!

Upvotes: 1

Views: 1141

Answers (1)

Andrew Walters
Andrew Walters

Reputation: 4803

This is described in the docs here: http://knockoutjs.com/documentation/custom-bindings-controlling-descendant-bindings.html

From the docs: Bindings such as with and foreach create extra levels in the binding context hierarchy. This means that their descendants can access data at outer levels by using $parent, $parents, $root, or $parentContext. If you want to do this in custom bindings, then instead of using bindingContext.extend(), use bindingContext.createChildContext(someData).

Example:

ko.bindingHandlers.withProperties = {
    init: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
        // Make a modified binding context, with a extra properties, and apply it to descendant elements
        var newProperties = valueAccessor(),
            childBindingContext = bindingContext.createChildContext(viewModel);
        ko.utils.extend(childBindingContext, newProperties);
        ko.applyBindingsToDescendants(childBindingContext, element);

        // Also tell KO *not* to bind the descendants itself, otherwise they will be bound twice
        return { controlsDescendantBindings: true };
    }
};

Upvotes: 7

Related Questions