4

The knockout website tells us how to access all the bindings of a particular element from inside a custom binding on that element.

However I want instead to get a list of all elements to which a particular named binding is applied. Is this possible through a knockout method?

For example, I'd like to ask knockout for a list of all elements on my page that use the visible binding.

John K
  • 28,441
  • 31
  • 139
  • 229
  • 1
    This question has hints of [XY Problem](http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem). Why do you think that's the solution to your problem? – Jamiec Jan 27 '15 at 20:24
  • @Jamiec, For tooling purposes, in a debug output section of my page I'd like to display a list of all elements having a particular binding and the count. I'd like to display this information using ko and not another framework and not pure script. – John K Jan 27 '15 at 20:32
  • Ok, seems sensible enough. Hope my comment wasnt taken the wrong way ;) – Jamiec Jan 27 '15 at 20:33
  • 1
    @Jamiec, not at all. It's not uncommon for questions to be framed in context of a preconceived solution direction that might not best fit the problem. I often do that, so in fact I'm glad you asked. – John K Jan 27 '15 at 20:35
  • Ive started a [jsfiddle](http://jsfiddle.net/rwtxje4g/) to try to investigate this. But to be honest im struggling, with that fiddle maybe someone else might have an idea. Think of the top level `div` as your html page (or any container element) and you're trying to get all elements bound with `visible` binding. One question is what you're trying to do with those elements once you have them? Anyway i'll keep having a look too. – Jamiec Jan 27 '15 at 20:43
  • @Jamiec With the elements I hope to print out some semi-useful info about them, or maybe even highlight them inline, however that's beyond the scope of my question. I just trying to find out if there's a way to get a list of them. – John K Jan 27 '15 at 20:57

1 Answers1

4

Interesting question!

I'm gonna go out here and say that you need to do the DOM traversal yourself. There is no Knockout util that does exactly what you want. And even then you'll have to hook deep into KO. This is based on some experience, as well as carefully peering through the KO TypeScript definition (which is a probably a near complete overview of KO's exported functionality).

Looking at the relevant bit in the definition, you can utilize the KnockoutBindingProvider like this:

var vm = {
  submodel: {
    name: ko.observable('apple'),
    description: ko.observable('fruit')
  },
  elementsWithTextBindings: ko.observable('')
};

vm.refresh = function() {
  var result = "";
  var all = document.getElementsByTagName("*");
  
  for (var i=0, max=all.length; i < max; i++) {
    var ctx = ko.contextFor(all[i]);
    
    if (ko.bindingProvider['instance'].nodeHasBindings(all[i])
        && !!ko.bindingProvider['instance'].getBindings(all[i], ctx).text) {
      var bindings = ko.bindingProvider['instance'].getBindingsString(all[i], ctx);
      result += "Elem with id=" + all[i].id + " has `text` binding ('" + bindings + "').\n";
    }
  }
  vm.elementsWithTextBindings(result);
};

ko.applyBindings(vm);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<div id="a" data-bind="with: submodel">
  <p id="b" data-bind="text: name, style: { color: 'red' }"></p>
  <p id="c" data-bind="text: description"></p>
  <input id="d" data-bind="value: name" />
</div>
All elements with `text` bindings:
<button id="e" data-bind="click: refresh">refresh!</button>
<pre id="f" data-bind="text: elementsWithTextBindings"></pre>

This utilizes the fact that you can reach ko.bindingProvider from the outside. This seems to be by design, as the source exports it with:

ko.exportSymbol('bindingProvider', ko.bindingProvider);

In my code I also utilize nodeHasBindings, and getBindings, and getBindingsString. The latter has a comment:

// The following function is only used internally by this default provider.
// It's not part of the interface definition for a general binding provider.

So I'd assume the first two methods are part o the public interface and can thus be safely used for your purposes. The getBindingsString isn't really necessary for your purpose anyways, but I've included in the example just for the example's sake.

Community
  • 1
  • 1
Jeroen
  • 60,696
  • 40
  • 206
  • 339