Search code examples
javascriptrazorknockout.js

How to call afterRender handler function in nested foreach?


I had foreach statement and used afterRender to call the function.

<div data-bind="foreach: { data: Object.keys(pricings()), as: '_propkey', afterRender: pricingTableRenderedHandler }">

During this iteration, _propkey was a single string. Then I had to change foreach statement to this :

<div data-bind="foreach: { data:  pricings(), as: '_propertykey', afterRender: pricingTableRenderedHandler}">
    <div data-bind="foreach: { data: _propertykey.states, as: '_secondarypropkey'}">

handler function

  self.pricingTableRenderedHandler = function (data, stateName) {
        var tableSelector = "#" + stateName.states.state.replace(/\s/g, '');

        hideEmptyTableColumns.hide(tableSelector);
        replaceEmptyTableCells.replaceBy(self.emptyCellValue, tableSelector);
  }

In case of old foreach, it received string in stateName parameter. Now, it receives an object that looks like this.

[ 
"cropYear" : "2020"
"states": [
    {
        "state": "Tbilisi",
        "details": {
            "PriceHeaders": [
            
            ],
            "Comment": "TBi",
            "Pricings": [
            ]
        }
    }
    {
        "state": "Texas",
        "details": {
            "PriceHeaders": [
               
            ],
            "Comment": "dasdsa",
            "Pricings": [
            ]
        }
    }
]

]

I only need to take "state" property value. I'm assuming that I need to call handler function in inner foreach but for some reason, I can not. Unless it is written in the first foreach, it does not get called.


Solution

  • The foreach binding creates a new binding context for every element. If, within the template you pass to foreach, you need to access a property of the original context, you can access that using $parent.

    <div data-bind="foreach: { 
                      data:  pricings(),
                      as: '_propertykey'
                    }">
      <div data-bind="foreach: {
                        data: _propertykey.states,
                        as: '_secondarypropkey'},
                        afterRender: $parent.pricingTableRenderedHandler">
        <!--                         ^^^^^^^^                          -->
      </div>
    </div>
    

    Note that the function will be called with the current element ($data) as this. If your handler relies on this, you can use $parent.methodName.bind($parent).