Frage

The clues for this question seem so hard to find that I begin to think it must be either obvious (and I'm missing something), useless, or impossible:

I get the 2-way binding thing in knockout with observables (ko.observables()). However all this parenthesis are a real pain. So as I'm using Durandal, I though I'd give the observableplugin a try : http://durandaljs.com/documentation/Binding-Plain-Javascript-Objects.html

(for the record, I also tried this one: http://blog.stevensanderson.com/2013/05/20/knockout-es5-a-plugin-to-simplify-your-syntax/)

Both are working fine with knockout's valuebinding.

My problem is I have multiple knockout custom bindings for my application and I don't get how you update an observable property that is not a ko.observable() in these custom bindings.

In my binding I would normally do this:

ko.bindingHandlers.testBinding = {
    init: function(element, valueAccessor) {
        var myObservable = valueAccessor();
        // here I could detect if it's an observable or a POJO
        // ... how to know if it's a property ???

        $(element).blur(function() {

            // ... how to write to myObservable if it's a writable property
            // ... and not a ko.observable() ???
            myObservable($(element).val());

        });

    },
    update: function(element, valueAccessor) {
        $(element).val(ko.unwrap(valueAccessor()));
    }
};

However with observables, I understand I'd need the reference to the underlying object and the name of the property to perform an update. (I can get the former but how to get the latter?)

I've looked into the value binding of knockout to try to understand but without more success...

Would someone have a simple example of how it would look like with the observable plugin? Any clue would be much appreciated.

Thanks

War es hilfreich?

Lösung

Using Knockout's preprocess feature, your binding can add a method to write to the property directly. Here's how you could do it:

ko.bindingHandlers.testBinding = {
    preprocess: function(value, name, addBindingCallback) {
        addBindingCallback('testBindingWriter', 'function(v){' + value + ' = v}');
        return value;
    },
    init: function(element, valueAccessor, allBindings) {
        var value = valueAccessor();
        $(element).blur(function() {
            if (ko.isObservable(value)) {
                value($(element).val());
            } else {
                allBindings.get('testBindingWriter')($(element).val());
            }
        });
    },
    update: function(element, valueAccessor) {
        $(element).val(ko.unwrap(valueAccessor()));
    }
};

Example: http://jsfiddle.net/mbest/U7Jeg/

Andere Tipps

If all you want to do is get the property name you can use preprocess to store it on the binding handler like this:

propertyName: null,
preprocess: (value) => {
        this.propertyName = value;
        return value;
},

You can now access the property in your init function and combine it with bindingContext to set the value:

init: (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) => {
        $(element).blur(() => {
            bindingContext.$data[this.propertyName] = $(element).val();
        })
}

Note: I'm using an arrow function above to preserve the meaning of "this." If that isn't an option for, you can do this instead:

init: (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) => {
        thisHandler = this;
        $(element).blur(function () {
            bindingContext.$data[thisHandler.propertyName] = $(element).val();
        })
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top