Skip to content

How to keep track of this of the parent component when calling a parent function inside a foreach loop in the template in knockout?

I have a cart-items-mixin.js

define(['Magento_Catalog/js/price-utils', 'Magento_Checkout/js/model/quote', 'ko',], function(priceUtils, quote, ko) {
    'use strict';

    return function(CartItems) {
        return CartItems.extend({
            (...)
            showDetails: ko.observable(false),

            handleShowDetails: function() {
                this.showDetails(true);
            },

            initialize: function() {
                this._super();
                (...);
            }
        });
    };
});

and the template:

<!--
/**
 * Copyright © Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */
-->
<div class="block items-in-cart">
  <!-- ko if: items().length -->
  <table class="table data products">
    <thead>
      <tr>
        <th class="label label--details is-hidden" data-bind="i18n: 'Product Name'"></th>
        <th class="label label--qty is-hidden" data-bind="i18n: 'Qty'"></th>
        <th class="label label--subtotal amount is-hidden" data-bind="i18n: 'Subtotal'"></th>
      </tr>
    </thead>
    <tbody data-bind="foreach: { data: items(), as: 'item' }, css: { 'collapsed': collapse }">
      <tr class="product">
        <!-- <td><pre data-bind="text: ko.toJSON(item, null, 2)"></pre></td> -->
        <td>
          <img class="product-image-photo" data-bind="attr: {src: 'https://www.haco.nu/media/catalog/product/cache/ab70b4d27ee7a1904aae155917a4a5ef/2/_/2_zits_bank_taupe_Aruba_3_2efd.jpg', alt: '2-zits Bank Aruba'}" />
        </td>
        <td class="product__details">
          <p data-bind="html: item.name"></p>
          <table class="table options" data-bind="foreach: { data: JSON.parse(item.options), as: 'option' }">
            <tbody>
              <!-- ko ifnot: ($parents[1].getProductType(item.item_id) === true && option.label === "Kleur") -->
              <!-- ko ifnot: (option.label == "Levertijd")-->
               <!-- ko if: (option.label == "Breedtemaat" || option.label == "Lengtemaat")-->
                <tr>
                  <td data-bind="html: option.value"></td>
                </tr>
               <!--/ko-->
                <!-- ko ifnot: (option.label == "Breedtemaat" || option.label == "Lengtemaat")-->
                 <!-- ko ifnot: (!$parents[1].showDetails())-->
                  <tr>
                    <td data-bind="html: option.value"></td>
                  </tr>
                    <!--/ko-->
                <!--/ko-->
              <!--/ko-->
              <!--/ko-->
            </tbody>
          </table>
          <button data-bind="click: $parent.handleShowDetails, visible: !$parent.showDetails(), text: 'Details'"></button>

        </td>
        <td class="product__qty" data-bind="html: item.qty"></td>
        <td class="product__subtotal amount" data-bind="html: $parent.formatPrice(item.row_total_incl_tax)"></td>
      </tr>
    </tbody>

    <td>
      <!-- ko if: items().length > 3 -->
       <button class="collapse-button" data-bind="css: { 'collapsed': collapse }, click: handleCollapse, text: collapse() ? $t('Show more') : $t('Show less')"></button>
      <!-- /ko -->
    </td>

  </table>
  <!-- /ko -->
</div>

I am trying to call the handleShowDetails inside the loop of the template:

<button data-bind="click: $parent.handleShowDetails, visible: !$parent.showDetails(), text: 'Details'"></button>

Using $parent allows me to call the function but the this is set to the loop instead of the Component object so the this.showDetails in

handleShowDetails: function() {
  this.showDetails(true);
},

now refers to this of the loop and is therefore now undefined. How can I keep track of the this of the Component object so that I can actually call this.showDetails()?

To solve this error:

cart-items-mixin.js:27 Uncaught 
TypeError: this.showDetails is not a function