I have a case in which I have nested loops in which the child one is constructed by a filter function that takes parent as the argument. I also have another filter that just
A much cleaner solution was suggested HERE.
What you need to do is wrap the relevant area with an ng-show / ng-if based on an expression that applies the filter on the data structure and extracts length. Here is how it works in your example:
<div ng-show="(materials | filter:filterByGroup(group)).length">
<div ng-repeat="group in groups">
{{group.name}}
<div ng-repeat="material in materials | filter:filterByGroup(group) | filter:search ">
{{material.name}}
</div>
</div>
</div>
This allows you to hide complex structures once they are empty due to filtering, e.g. a table of results.
If you can ask for the materials by group and you expect to do that for each group anyway, why not do that right away when you initialize the view and build a model with groups that have materials? If you can do that you can use ng-show to only hide groups that have materials.
You seem to need to know that a group has materials or not somehow? Here's a fiddle without knowing much of the background story:
<div ng-controller="MyCtrl">
<div ng-repeat="group in groups">
<div ng-show="groupHasMaterials(group)">{{group.name}}</div>
<div ng-repeat="material in materialsByGroup(group)">
<div>{{material.name}}</div>
</div>
</div>
</div>
<script>
var myApp = angular.module('myApp',[]);
function MyCtrl($scope) {
var groups = [
{'name':'group one'},
{'name':'group two'}
];
var materials = [
{'name':'material1'},
{'name':'material2'},
{'name':'material3'}
];
$scope.groups = groups;
$scope.materials = materials;
$scope.groupHasMaterials = function(group){
return $scope.materialsByGroup(group).length > 0;
}
$scope.materialsByGroup = function(group){
return group.name === 'group one'
? [materials[0], materials[1]]
: [];
}
}
</script>
fiddle with groups
I've seen this use-case a few times, here's my solution:
<div ng-repeat="group in groups">
<div ng-repeat="material in materials | filter:filterByGroup(group) | filter:search ">
<span ng-show="$first">
{{group.name}}<br/>
</span>
{{material.name}}
</div>
</div>
You can use $first or $last within the scope of the ng-repeat to show only for the first and last of each group. if there is no $first, it won't show the group name.
I just implemented this on my blog and updated your fiddle here: http://jsfiddle.net/ke793/1/
I'm not sure if this is the most elegant solution, but it seems fairly simple and it works. I'd love to see how others solved this.
Update: just realized you can use ng-if
to prevent the group name from hitting the dom at all outside of the $first
element. Little bit cleaner than ng-hide/ng-show, which sets display: none
to the extra header every time.