How do I only show an element if nested ng-repeat is not empty?

前端 未结 6 1925
没有蜡笔的小新
没有蜡笔的小新 2020-12-25 11:01

I have a List of lists, created with a nested ng-repeat. Each outer ng-repeat contains a div with the label of its inner list (eg: \"Group A\"). I\'m now trying to create a

相关标签:
6条回答
  • 2020-12-25 11:23

    you could leverage ng-init, that way you'll call the filter only once:

    <div ng-repeat='(key,group) in model'>
      <div ng-init="filtered = (group | filter:filterFn)"></div>
      <div ng-show="filtered.length !== 0">
        <div>{{key}}</div>
        <ul>
          <li ng-repeat="el in filtered">
            <div>{{el.label}}</div>
          </li>
        </ul>
      </div>
     </div>
    

    usually it is not a good practice to use ng-init out of no where, but I guess it solves calling the filter twice. Another way is to use the filter through javascript - you could inject $filter and retrieve 'filter' $filter('filter') in your controller, calling it with group as its first argument, the filterFn as its second, and store its result in your scope.

    0 讨论(0)
  • 2020-12-25 11:23

    checking if an array has a length of 0 is not an expensive operation. if you want to only show lists that have item, put a filter on the outer array that takes an array of arrays and returns only the arrays that have a length different than 0.

    you can also hide the inner div if the array == false.

    http://plnkr.co/edit/gist:3510140

    http://plnkr.co/edit/Gr5uPnRDbRfUYq0ILhmG?p=preview

    0 讨论(0)
  • 2020-12-25 11:33

    I ended up with the following solution which worked perfectly. Plnkr

    By setting a variable in the inner ng-repeat I was able to evaluate ng-show based on this variables length like so :

    <input ng-model='searchText'/>
    <span ng-show='filtered.length > 0'>
      <ul>
        <li ng-repeat='el in filtered = (model | filter:searchText)'>
          <div>{{el.label}}</div>
        </li>
      </ul>
    </span>
    
    0 讨论(0)
  • 2020-12-25 11:34

    I used the following:

    <ul>
        <li ng-repeat="menuItem in menuItems"><a href="Javascript:void(0);"><span class="fa {{menuItem.icon}} fa-lg"></span>{{menuItem.itemName}}</a>
        <span ng-show='menuItem.subItems.length > 0'>
            <ul>
                <li ng-repeat="subItem in menuItem.subItems"><a href="Javascript:void(0);">{{subItem.itemName}}</a></li>
            </ul>
        </span>
    </li>
    

    0 讨论(0)
  • 2020-12-25 11:39

    I have only slightly modified your list-widget.html, see it in action: plunkr

    The idea is simple - use the same filter for ng-show:

    <div ng-show="group | filter:searchText">{{ key }}</div>
    

    The label will be visible only if there are some unfiltered items.

    In my example I'm using searchText for filter because I'm not familiar with CoffeeScript.

    0 讨论(0)
  • 2020-12-25 11:40

    Your plunkr was pretty complicated and hard to weed through so I re-created what you wanted using a fiddle. The general idea behind my approach is to filter out the items from the array, not the sub array. And only do the filtered items when the text changes. So here's the markup:

    <div ng-app="app">
        <div ng-controller="ParentCtrl">
            <input data-ng-model="filterText" data-ng-change="updateTypes()" />
            <div data-ng-repeat="type in filteredTypes">
                {{ type.name }}
                <ul>
                    <li style="margin-left:20px;" data-ng-repeat="entry in type.entries">
                        - {{ entry.name }}
                    </li>
                </ul>
            </div>
        </div>
    </div>
    

    And here's the code:

    angular.module('app', [])
    
    function ParentCtrl($scope){
        $scope.filterText = "";
        $scope.types = [
            { name: "type1", entries: [{ name: "name1"}, { name: "name2"}, { name: "name3"}]},
            { name: "type2", entries: [{ name: "name1"}, { name: "name3"}, { name: "name3"}]},
            { name: "type3", entries: [{ name: "name1"}, { name: "name2"}, { name: "name5"}]},
                { name: "type4", entries: [{ name: "name4"}, { name: "name2"}, { name: "name3"}]}
        ];
    
        $scope.filteredTypes = [];
        $scope.updateTypes = function(){
            $scope.filteredTypes.length = 0;
            for(var x = 0; x < $scope.types.length; x++){
                if($scope.filterText === ""){
                    $scope.filteredTypes.push($scope.types[x]);    
                }
                else{
                    var entries = [];
                    for(var y = 0; y < $scope.types[x].entries.length; y++){
                        if($scope.types[x].entries[y].name.indexOf($scope.filterText) !== -1){
                           entries.push($scope.types[x].entries[y]);   
                        }                        
                    }
                    if(entries.length > 0){
                        $scope.filteredTypes.push({
                            name: $scope.types[x].name,
                            entries: entries
                        });
                    }
                }
            }
        }
        $scope.updateTypes();
    }
    

    Fiddle: http://jsfiddle.net/2hRws/

    The reason I'm creating a new array and not using an actual filter to remove the results is that angular doesn't like creating dynamic arrays on the fly in filters. This is because it doesn't assign $$hashKey and things just don't line up correctly when dirty checking. I got the idea of how to do what you needed from this topic on the matter: https://groups.google.com/forum/#!topic/angular/IEIQok-YkpU

    0 讨论(0)
提交回复
热议问题