javascriptknockout.jsjavascript-framework

Knockout.js hasfocus causes value to be reset when losing focus before the throttle period expires


Here is a little sample code which illustrates my problem: http://jsfiddle.net/wsytR/2/

If you change the text in the input and then press tab to blur it the value changes back to the old one. This happens if you switch focus before the throttle period is over. It seems to me the observable isn't getting changed at all in this way.

I found this question and from it got to this issue. I reordered the bindings so that hasfocus is the first one, but no luck with that.

Also if instead of pressing tab to switch focus you press Escape or just click somewhere else on the page, the old value is restored again, but after the throttle period expires the observable gets updated and the value changes yet again, this time to the new one. Probably a different kind of event is triggered by tab and Escape/click.

Is there a way to handle this with knockout? Am I trying to do something wrong or something that should not be expected to work in knockout?

Edit:

Turns out I have not formulated my question correctly. I need the focus to be set from my model, so throttling the hasfocus binding does not solve my issue. If you just need to have it update properly after you leave the element but still keeping the throttle, that works great.

My goal is to get immediate update upon losing focus, but otherwise throttle the binding while till typing.


Solution

  • The built-in throttle extender in knockout does just what its name says it does: it throttles updates. Seems I wanted to do something else. Getting the value to update instantly upon blurring the field, but otherwise throttle the input while typing.

    The solution I finally came up with was tweaking the built-in throttle extender and adding that as a custom extender:

    ko.extenders.smart_throttle = function(target, timeout) {
        target['throttleEvaluation'] = timeout;
        target['lastUpdatedValue'] = null;
    
        var writeTimeoutInstance = null;
        return ko.computed({
            'read': target,
            'write': function(value) {
                if (value == target()) {
                    clearTimeout(writeTimeoutInstance);
                    target(target['lastUpdatedValue']);
                    return;
                }
    
                clearTimeout(writeTimeoutInstance);
                target['lastUpdatedValue'] = value;
                writeTimeoutInstance = setTimeout(function() {
                    target(value);
                }, timeout);
            }
        });
    }
    

    Akshat's answer is still a perfect solution to my original question. Sorry about not formulating it correctly though.