90

In knockout.js 2.1.0, in a template using the foreach binding, you can access the current item's index though the $index() function. In a nested foreach binding, is there any way to access the index of the $parent from a template?

Say I have a data structure like this:

var application = {
  topModel: [
    {
      {subModel: [{'foo':'foo'}, { 'bar':'bar'}]}, // this has top:0 and sub:0
      {subModel: [{'foo2':'foo2'}, { 'bar2':'bar2'}]} // this has top:0 and sub:1
    },
    {
      {subModel: [{'foo':'foo'}, { 'bar':'bar'}]} // this is top:1 sub:0
    },
    {
      {subModel: [{'foo':'foo'}, { 'bar':'bar'}]} // this is top:2 sub:0
      {subModel: [{'foo':'foo'}, { 'bar':'bar'}]} // this is top:2 sub:1
    },
    ...
    ]};

With this, I want to print the path to each model, using indices: [topModel-index subModel-index], so that the output will be something like:

[0 0]
[0 1]
[1 0]
[2 0]
[2 1]
...

I have bound the models using foreach, but I can't figure out how to access the topModel's index in the context of the subModel. The following example shows an approach I have tried, but it doesn't work, as I can't figure out how to access the index of the $parent referrer.

<!--ko foreach: topModel -->
<!--ko foreach: subModel -->
  [<span data-bind="text: $parent.index()"></span>
  <span data-bind="text: $index()"></span>]
<!--/ko-->
<!--/ko-->

Should print out: 0 1, 0 2, 1 0, 1 1, 1 2, 2 0, 2 1, ...

Jørgen
  • 8,820
  • 9
  • 47
  • 67

2 Answers2

191

to access the index of the parent object use

$parentContext.$index()

rather than

$parent.index()
Beau Nouvelle
  • 6,962
  • 3
  • 39
  • 54
Brett Smith
  • 2,992
  • 1
  • 20
  • 22
  • 14
    Though, to be overly explicit in the name of brainlessness, you still have to `$parentContext.$index()` with the parens. ;^) A little more on $parentContext [here](http://www.appliness.com/10-things-to-know-about-knockout-js-on-day-one/), fwiw. – ruffin Jul 22 '13 at 16:20
  • @ruffin not for $index, as per Matthew's comment on the original question "you don't actually need that () after the $index there." $index is a special variable rather than an observable. – Brett Smith Jul 22 '13 at 21:34
  • When I used `$parentConsent.$index` sans `()` in a template, I get the function underlying it through an implicit `toString`. Working code snippet (that doesn't eval to the function's string representation): `attr: { id: 'field' + $parentContext.$index() + '-' + $index() }"` – ruffin Jul 23 '13 at 18:44
  • 3
    thanks - definitely worth noting, in the context of a composite value you would need to add the () however if you were binding an element to the $parentContext.$index as per the question you don't need it. – Brett Smith Jul 23 '13 at 23:24
  • 5
    Need parentheses `$parentContext.$index()` – Jaider Nov 09 '13 at 02:06
  • 4
    Just wanted to add that `$parentContext.$parentContext.$index()` works as you would expect too. – Ryan Wheale Nov 24 '14 at 00:42
3

The easiest way you can find out is download "knockout context" for chrome. This shows you what data is bound to what element and also lets you see the available functions/variables to that particular bound element. It's an amazing tool for situations like these.

Julian
  • 781
  • 1
  • 11
  • 32