Monday, September 16, 2013

AngularJS - Accessing parent scope's variables/model inside nested ng-repeat


Hi,

Working with nested ng-repeat's can be tricky, here's a issue I ran into while I was designing html with nested ng-repeat.

Problem: Say I have scenario in which I have to design the template in such a way that the template is nested in itself.

<script type="text/ng-template" id="template.html">
 <div>{{data.name}}</div>
    <ul>
        <li ng-repeat="data in data.Children" ng-include="'template.html'" ></li>
    </ul>
</script>

This is our data which is bound to the template.

[{
  "id": "6000", "Name": "All Categories",
    "Children": [{
      "id": "6100", "Name": "Juice",
        "Children": [{
          "id": "6200", "Name": "Mom's Brands",
            "Children": [{ "id": "6454", "Name": "Mom's Apple Jug" },
              { "id": "6456", "Name": "Mom's Apple Juice" },
              { "id": "6458", "Name": "Mom's Grape Juice" },
              { "id": "6462", "Name": "Mom's Apple Grape Jug" },
              { "id": "6463", "Name": "Mom's Pear Blend" },
              { "id": "6464", "Name": "Mom's Juice Cocktail Lite" }
        ]
      }]
    }]
  }]

Now I have a model(say $scope.dontShowID = "6454") in controller based on which I need to check some condition to display or not to display the "<li>". And hence I modified the template code as follows.

<li ng-show="data.ID!=dontShowID" ng-repeat="data in data.Children" ng-include="'template.html'" ></li>

The above code doesn't work because ng-repeat creates its own scope and hence we might have to access parent's scope to access dontShowID. So to access parent's scopes the code will change as.

<li ng-show="data.ID!=$parent.dontShowID" ng-repeat="data in data.Children" ng-include="'template.html'" ></li>

Since this is a nested template our data will also be in nested form. Everytime there's a ng-repeat a new scope is created, in such a case the above code will not work as $parent will have reference to the parent ng-repeat's scope.

Now here's the problem to access dontShowID at each level of data. Even if we know the level at which data is it is difficult to access controller scope's model.

But somehow this rule doesn't apply to methods.

Solution: Nearest decent solution I have been able to find is to add a init method just before ng-repeat i.e, at {{data.name}} and pass data as argument to the init method. Inside the init method assign the dontShowID to data.dontShowID.

So the code will change as.

<script type="text/ng-template" id="template.html">
 <div ng-init="initData(data)">{{data.name}}</div>
    <ul>
        <li ng-show="data.dontShowID!=data.ID" ng-repeat="data in data.Children" ng-include="'template.html'" ></li>
    </ul>
</script>

And the code of initData method will be...

$scope.initData = function (data) {
    data.dontShowID = $scope.dontShowID;
};

Once we assign the model at the data level, the condition checking is easy as we no longer need to access parent scope. Hope this helps in solving ng-repeat scope issues. This is the solution I have found so far, any thoughts on how we can improve this?

No comments:

Post a Comment