Как я могу показать только элемент, если вложенный ng-repeat не пуст?
У меня есть список списков, созданных с помощью вложенного ng-repeat. Каждый внешний ng-repeat содержит div с меткой его внутреннего списка (например: "Группа A" ). Теперь я пытаюсь создать способ избежать отображения этой метки, если внутренний список пуст из-за фильтрации (применяется с помощью входного поискового текста)
Вот плункер, объясняющий мою проблему и мое попытку: Plnkr
Наличие "тяжелой" функции, такой как isGroupEmpty, кажется чрезвычайно громоздкой - есть ли способ сделать это гораздо проще? Я играл с идеей переместить ярлык внутри внутреннего ng-repeat и иметь ng-show="$first"
, но он не выглядит великолепно
Ответы
Ответ 1
У меня получилось следующее решение, которое отлично работало. Plnkr
Установив переменную во внутреннем ng-повторе, я смог оценить ng-show на основе этой длины переменных следующим образом:
<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>
Ответ 2
вы можете использовать ng-init
, таким образом вы будете вызывать фильтр только один раз:
<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>
обычно не рекомендуется использовать ng-init
вне, но я думаю, что он решает вызвать фильтр дважды.
Другой способ - использовать фильтр через javascript - вы можете вставить $filter и получить "filter" $filter('filter')
в своем контроллере, вызвав его как группу в качестве первого аргумента, filterFn в качестве второго и сохраните его результат в своей области.
Ответ 3
Я использовал следующее:
<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>
Ответ 4
проверка, если массив имеет длину 0, не является дорогостоящей операцией. если вы хотите показывать только списки с элементом, поместите фильтр во внешний массив, который принимает массив массивов и возвращает только массивы с длиной, отличной от 0.
вы также можете скрыть внутренний div, если массив == false.
http://plnkr.co/edit/gist:3510140
http://plnkr.co/edit/Gr5uPnRDbRfUYq0ILhmG?p=preview
Ответ 5
Ваш plunkr был довольно сложным и трудным для сорняков, поэтому я снова создал то, что вы хотели, используя скрипку. Основная идея моего подхода состоит в том, чтобы отфильтровать элементы из массива, а не в подвале. И только элементы, отфильтрованные при изменении текста. Итак, здесь разметка:
<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>
И вот код:
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/
Причина, по которой я создаю новый массив и не использую фактический фильтр для удаления результатов, заключается в том, что angular не нравится создавать динамические массивы "на лету" в фильтрах. Это связано с тем, что он не присваивает $$ hashKey, и вещи просто не выстраиваются правильно при грязной проверке. Я получил представление о том, как сделать то, что вам нужно от этой темы по этому вопросу: https://groups.google.com/forum/#!topic/angular/IEIQok-YkpU
Ответ 6
Я немного изменил ваш list-widget.html
, посмотри его в действии: plunkr
Идея проста - используйте тот же фильтр для ng-show
:
<div ng-show="group | filter:searchText">{{ key }}</div>
Метка будет видна только в том случае, если есть некоторые нефильтрованные элементы.
В моем примере я использую searchText
для фильтра, потому что я не знаком с CoffeeScript.