<div data-bind="myHandler, visible: !enabled()"> </div>So in general, you have access to all the other bindings when inside a bindinghandler:
ko.bindingHandlers.myHandler = { init: function(element, valueAccessor, allBindings, viewModel, bindingContext) { var visible = allBindings().visible; } };The problem with calling allbindings().someBinding, is that you get the *result* of the binding. In my case, I wanted to subscribe to when any updates happen to the entire binding: "visible: !enabled()"
Knockout handles this for a normal bindingHandler in the update function. If the valueAccessor changes, update gets fired.
So I needed to have a way to get access to the valueAccessor of a different bindingHandler on the same node. The solution I came up with involved asking the knockout bindingProvider to give me the value accessors, then subscribing to the valueAccessor I wanted to listen to:
ko.bindingHandlers.myHandler = { init: function(element, valueAccessor, allBindings, viewModel, bindingContext) { var bindingAccessors = ko.bindingProvider.instance.getBindingAccessors(element, bindingContext), visibleAccessor = bindingAccessors.visible, myObservable = viewModel.someObservable; // For complex reasons, this observable needs to update based on another binding in the same node if (visibleAccessor) { // This simulates what the knockout update bindingHandler does: ko.computed(function() { myObservable(ko.unwrap(visibleAccessor)); // the computed fires because we have visibleAccessor in our scope }); } } };
So now when the visible binding updates, we get the result of the valueAccessor instead of a single result at one point in time of a valueAccessor (shown in the first js code block).
I know this sounds complicated, but this was exactly what I was looking for to be able to access the valueAccessors of the same node. Using allBindings().someHandler was forcing me to make trivial pureComputed variables:
var MyViewModel = function() { this.enabled = ko.observable(false); this.disabled = ko.pureComputed(function() { return !this.enabled(); }, this); }
I really wanted this trivial code to exist in the template, not in the viewModel. So the solution using getBindingAccessors allows me to keep this code in the templates.
Great solution! I was freaking out with the visible binding... One would believe that the `allBindings` parameter contains the accessors, not the values.
ReplyDelete