1

I have a custom binding that is used to re-initialise a dom element whenever a field ("Type") is changed on the viewmodel. This is defined in an update callback.

<input type="text" data-bind="value: Value, initValueField: Type()" />

ko.bindingHandlers.initValueField = {
    update:function (element, valueAccessor, allBindingsAccessor, viewModel) {
        alert('Hello World');
    }
};

See this jsFiddle for a stripped down demo.

As I understand it, one of the conditions for the update being invoked is the following:

The mechanics of custom bindings

Any time that another binding in the same data-bind attribute is triggered. This helps ensure things like the value is appropriate when the options are changed.

The issue I have is that this update callback is also called whenever the value on the viewmodel changes.

So...is it possible to either:

  1. Suppress one of the bindings from invoking the custom binding.
  2. Detect the source of the invocation inside the custom binding.
Brett Postin
  • 11,215
  • 10
  • 60
  • 95
  • Why do you need a custom binding for this? Can't you just subscribe to the type observable and set the value of your field there? Another solution would be to override the value binding – thomaux Nov 26 '12 at 14:40
  • 1
    My custom binding sets up the input field with a jQuery UI component based on the Type member. Whenever this Type member changes I may need to change the UI component (e.g. change from Datepicker to Autocomplete). I have this working, however the custom binding also fires whenever the Value member changes. If you think a custom binding isn't necessary, I'd be grateful if you could post the alternative. – Brett Postin Nov 26 '12 at 14:50
  • In that case, a custom binding is a good solution. I just asked because it was not entirely clear what you were trying to achieve. I need to think about this a sec. – thomaux Nov 26 '12 at 15:02

3 Answers3

1

I found potential workarounds to the problem here:

Knockout.js Performance Gotcha #3 - All Bindings Fire Together

The options are:

  1. Split the bindings up by putting them onto separate elements (maybe a container element).
  2. Similar to point 1, but use containerless bindings to separate them out.
  3. Use a computed observable in the custom binding init to manage the updates manually.
Brett Postin
  • 11,215
  • 10
  • 60
  • 95
0

you can perhaps check for changes of the observable. And only then execute the action. Something like this:

(function () {
    var cache;
    ko.bindingHandlers.initValueField = {
        init:function (element, valueAccessor, allBindingsAccessor, viewModel) {
            var currentValue = valueAccessor();
            cache = currentValue();
        },
        update:function (element, valueAccessor, allBindingsAccessor, viewModel) {
            var currentValue = valueAccessor();
            if (cache !== currentValue()) {
                alert('Hello World');
                cache = currentValue();
            }
        }
    };
}());

The cache variable stores the old value of the observable. The alert is only done when the current value is different from this old one.

the working fiddle: http://jsfiddle.net/DMLzd/6/

gbs
  • 3,529
  • 2
  • 20
  • 18
0

You can use element argument in your custom binding to see the DOM element that invokes that binding. See http://jsfiddle.net/DMLzd/7/ for conditional within your custom binding which uses id attribute of textbox to decide whether to perform actions or not. I added additional textbox and button with different ID that invokes the custom binding.

alekperos
  • 566
  • 4
  • 10