value of relevant observable in event function

70 views
Skip to first unread message

gaffe

unread,
Nov 19, 2012, 3:53:28 PM11/19/12
to knock...@googlegroups.com
Hi everyone,

Does anyone know how to get the value of the value observable in an event binding?

For example I have a text field with the following binding:

data-bind="value: myObservable, event: {keypress: PlaintextCharsOnly }"

and a function like:

var PlaintextCharsOnly = function (observable, event) {
    var str = replaceMSWordChars(observable()); //need to do this first to convert characters that we want to keep like quotes and doublequotes, etc.

   //remove all non-English, non-basic characters users keep pasting in, I don't want them in my DB or reports..
    for (var i = 0; i < str.length; i++) {
        if (!(str.charCodeAt(i) == 10 || str.charCodeAt(i) == 20 || (str.charCodeAt(i) >= 32 & str.charCodeAt(i) <= 126))) {
            str = str.slice(0, i) + str.slice(i + 1, str.length);
            i--;
        }
    }
    observable(str);
}

But $data being passed into the event function is not the same as myObservable.

How can I make it so? I solved this problem by wrapping it in an anonymous function then specifying myObservable name explicitly AGAIN inline, but this is really messy and I feel like I am missing something. I need to do this on many, many fields so is there any way to get the current observable value? 

Thanks!

P.S. I tried to make a custom binding out of this like so:

ko.bindingHandlers.replacebadChars = {
    update: function (element, valueAccessor, allBindingsAccessor, viewModel) {
        var bindingValue = ko.utils.unwrapFunction(valueAccessor);

        if (bindingValue) {
            if (allBindingsAccessor().value() != null) {
                $(element).val(PlaintextCharsOnly(allBindingsAccessor().value,event)); //update DOM - not sure why I should need to do this, but just updating the observable via the line below doesn't always update DOM correctly..
                allBindingsAccessor().value($(element).val()); //update viewModel
            }
        }
    }
}

Anyone know why I have to explicitly set the value like this, and/or if there is a better way to make this binding since right now the binding only triggers once the field is blurred and I want this to run also on keypress (but I don't want to set ValueUpdate because I don't want all my code to happen on every keypress just this).

basil.za...@gmail.com

unread,
Dec 2, 2012, 6:12:49 AM12/2/12
to knock...@googlegroups.com

What you probably want to make is extender, like in that example: http://knockoutjs.com/documentation/extenders.html#live_example_1_forcing_input_to_be_numeric

But any update of observable value will cause "all code to happen" anyway and likely more than once. So, if you really need to filter user input on key press, but update value in the model on focus blur, you’ll have to apply the filtering outside of knockout’s model, e.g., in jQuery event handler. 

And you’d better filter those characters with regular expression.

gaffe

unread,
Dec 3, 2012, 4:08:59 PM12/3/12
to knock...@googlegroups.com, basil.za...@gmail.com
I use an extender to make input numeric and this is handy, but how can I turn an extender into a custom binding? Trying to monkey with the mapping to extend each of the relevant observable in a large structure is painful. Being able to specify it as a custom binding would make the code much easier/cleaner. 

Is it possible to make a custom binding that simply extends the value observable in the init? I'll take a crack at it and post it on here if I get it to work.

Thanks!

gaffe

unread,
Dec 3, 2012, 6:05:10 PM12/3/12
to knock...@googlegroups.com, basil.za...@gmail.com
Does anyone know why the following code gives the error Uncaught TypeError: Object 1200 has no method 'extend'
on the line    allBindings = allBindings.value().extend({ numericNotNegative: '' }); ?

I have an extender that works correctly called numericNotNegative and I just want to make a custom binding that applies it to the observable passed into value. 

Please help.

Thanks!

My code: 

ko.extenders.numericNotNegative = function (target) {
    //create a writeable computed observable to intercept writes to our observable
    var result = ko.computed({
        read: function () {
            if (target() == "0")
                return '';
            else
                return target();
        },  //always return the original observables value
        write: function (newValue) {
            var current = target();
            var realNumber = rawNumber(newValue.toString().replace("-", ""));
            var valueToWrite = number_format(realNumber);

            //only write if it changed
            if (valueToWrite !== current) {
                target(valueToWrite);
            } else {
                //if the rounded value is the same, but a different value was written, force a notification for the current field
                if (newValue != current) {
                    target.notifySubscribers(valueToWrite);
                }
            }
        }
    });

    //initialize with current value to make sure it is rounded appropriately
    result(target());

    //return the new computed observable
    return result;
};

ko.bindingHandlers.numeric = {
    init: function (element, valueAccessor, allBindingsAccessor, passedInViewModel) {
        var allBindings = allBindingsAccessor();

        if (valueAccessor()) {
            allBindings = allBindings.value().extend({ numericNotNegative: '' });
        }

    }
}
Reply all
Reply to author
Forward
0 new messages