81

Updated for brevity

How can I reference the $parents' $parent in nested Knockout foreach / with bindings?

Example -

    <!-- ko foreach: grandParent -->
        <tr>
            <!-- ko foreach: $parent.parents --> // <-- Doesn't work
                <!-- ko foreach: children -->
                    <td data-bind="if: favToy().name == $parent.$parent.favToy().name">
                        <span data-bind="text: favToy().name"></span>
                    </td>
                <!-- /ko -->
            <!-- /ko -->
        </tr>
    <!-- /ko -->

Original

Sorry for the confusing question but I am trying to reach a second level parent's value to check against a value in the current context (like below) to only show a span if it matches a $parent's $parent's value (ugh!)

    <!-- ko foreach: grandParent -->
        <tr>
            <!-- ko foreach: $parent.parents -->
                <!-- ko foreach: children -->
                    <td data-bind="if: favToy().name == $parent.$parent.favToy().name">
                        <span data-bind="text: favToy().name"></span>
                    </td>
                <!-- /ko -->
            <!-- /ko -->
        </tr>
    <!-- /ko -->

It would be easier to do it this way but from what I have read this is not possible or I am doing it wrong :)

    <!-- ko foreach: grandParent -->
        <tr>
            <!-- ko foreach: $parent.parents -->
                <!-- ko foreach: children ? favToy().name == $parent.$parent.favToy().name -->
                    <td  data-bind="text: favToy().name"></td>
                <!-- /ko -->
            <!-- /ko -->
        </tr>
    <!-- /ko -->

Any help would be greatly appreciated.

PW Kad
  • 14,953
  • 7
  • 49
  • 82
  • I don't understand your question, what is not working? What is your problem: is the syntax of `$parent.$parent` or that you must use `span` because you cannot merge the `foreach` and the `if`? – nemesv Jun 12 '13 at 15:34

3 Answers3

141

Use the $parents array, the grandparent would be $parents[1]. You may also be able to use $root if the grandParent object in your example is the topmost parent.

From the docs:

$parents

This is an array representing all of the parent view models:

$parents[0] is the view model from the parent context (i.e., it’s the same as $parent)

$parents[1] is the view model from the grandparent context

$parents[2] is the view model from the great-grandparent context

… and so on.

$root

This is the main view model object in the root context, i.e., the topmost parent context. It’s usually the object that was passed to ko.applyBindings. It is equivalent to $parents[$parents.length - 1].

Andrew
  • 12,991
  • 15
  • 55
  • 85
Matt Burland
  • 44,552
  • 18
  • 99
  • 171
  • For some reason `$parent.$parent` did not work for me, this solution however worked fine, and it's shorter too! – PeterM Sep 27 '17 at 21:00
10

You can use $parentContext.$parent.

$parentContext provide many useful properties such as ($data, $parent, $index, ...)

Hassan Alhaj
  • 333
  • 3
  • 11
  • In my cases, I had a foreach inside of a foreach and wanted to access the $index of the 1st one from the 2nd loop. $parentContext.$index() worked! – chri3g91 Jul 22 '21 at 08:09
0

I think it would be easier to use the noChildContext setting like this:

Using “as” without creating a child context

The default behavior of the as option is to add a name for the current item while still also binding the contents to the item. But you may prefer keep the context unchanged and only set the name of the current item. This latter behavior will probably be the default in a future version of Knockout. To turn it on for a specific binding, set the noChildContext option to true. When this option is used along with as, all access to the array items must be through the given name, and $data will remain set to the outer viewmodel. For example:

<ul data-bind="foreach: { data: categories, as: 'category', noChildContext: true }">
    <li>
        <ul data-bind="foreach: { data: category.items, as: 'item', noChildContext: true }">
            <li>
                <span data-bind="text: category.name"></span>:
                <span data-bind="text: item"></span>
            </li>
        </ul>
    </li>
</ul>

Read more here

cjohansson
  • 1,058
  • 10
  • 13