angular ng-repeat пропустить элемент, если он соответствует выражению

91

Я ищу способ указать angular пропустить элемент в ng-repeat, если он соответствует выражению, в основном continue;

В контроллере:

$scope.players = [{
    name_key:'FirstPerson', first_name:'First', last_name:'Person'
}, {
    name_key:'SecondPerson', first_name:'Second', last_name:'Person'
}]

Теперь в моем шаблоне я хочу показать всех, кто не подходит name_key='FirstPerson'. Я решил, что это должны быть фильтры, поэтому я установил Plunkr, чтобы поиграть с ним, но мне не повезло. Plunkr Попытка

aron.duby
источник
Я пытаюсь понять: вы хотите показать все элементы, но указать, кто соответствует, а кто нет? или просто фильтровать?
Максим Шустин 05

Ответы:

144

Как предложил @Maxim Shoustin , лучший способ добиться того, чего вы хотите, - это использовать настраиваемый фильтр.
Но есть и другие способы, один из которых - использовать ng-ifдирективу для того же элемента, в котором вы поместили ng-repeatдирективу (также здесь плункер ):

<ul>
    <li ng-repeat="player in players" ng-if="player.name_key!='FirstPerson'"></li>
</ul>

Это может представлять незначительный недостаток с эстетической точки зрения, но имеет большое преимущество, заключающееся в том, что ваша фильтрация может быть основана на правиле, которое не так тесно связано с playersмассивом и которое может легко получить доступ к другим данным в области вашего приложения:

  <li 
      ng-repeat="player in players" 
      ng-if="app.loggedIn && player.name != user.name"
  ></li>

Обновление
Как уже говорилось, это одно из решений такого рода проблем, которое может соответствовать вашим потребностям, а может и не соответствовать.
Как указано в комментариях, ng-ifэто директива, которая на самом деле означает, что в фоновом режиме она может выполнять больше действий, чем вы могли ожидать.
Например, ng-if создает новую область видимости из ее родителя :

Область видимости, созданная в ngIf, наследуется от своей родительской области с использованием прототипного наследования.

Обычно это не влияет на нормальное поведение, но во избежание непредвиденных ситуаций вы должны помнить об этом перед внедрением.

gion_13
источник
это было именно то, что я искал, знал, что должен быть какой-то короткий и приятный способ сделать это без специального фильтра. Благодарность!
aron.duby 06
Примечание: есть некоторые варианты поведения ng-if, которые могут быть непростыми. Я попробовал этот метод, и он вызвал проблемы в другом месте. А именно, у меня есть директива «наблюдателя», которая транслирует событие, когда ретранслятор закончил работу. После добавления ng-if к этому повторителю он больше не запускал это событие. Пользовательский фильтр на самом деле может быть самым чистым способом.
Claywhipkey
@claywhipkey, ты прав, самый чистый способ - использовать фильтр, но он подходит не для всех случаев. Во всяком случае, ТНХ для комментария и вы можете увидеть , что я добавил головы вверх обновление в ответ просто заставить кого -то знать о последствиях использования директивы для фильтрации данных.
gion_13
43

Я знаю, что это старый, но на случай, если кто-то будет искать другое возможное решение, вот другой способ решить эту проблему - использовать стандартные функции фильтра :

Объект: объект шаблона можно использовать для фильтрации определенных свойств объектов, содержащихся в массиве. Например, предикат {name: "M", phone: "1"} вернет массив элементов, имя свойства которых содержит "M", а свойство phone содержит "1". ... Предикат можно отрицать, добавив к строке префикс!. Например, предикат {name: "! M"} вернет массив элементов, имя свойства которых не содержит "M".

Итак, для примера TS должно быть что-то вроде этого:

<ul>
    <li ng-repeat="player in players | filter: { name_key: '!FirstPerson' }"></li>
</ul>

Нет необходимости писать собственные фильтры, нет необходимости использовать ng-ifс новой областью действия.

Илья Лузянин
источник
Просто по делу. Как заявил автор, пользовательский фильтр или новая область не созданы. Идеально подходит для пропуска одного значения в списке.
mbokil
Я думаю, вам нужно опустить 'player' из 'player.name_key' - так что в приведенном выше примере это будет просто «{name_key: '! FirstPerson'}».
smithml
Мне никогда не удавалось заставить Angular хорошо работать с пустыми клавишами. Есть ли какой-то трюк для использования встроенных фильтров для эквивалента player in players | filter: { name_key: '' }? Эта конкретная директива не будет соответствовать только игрокам, у которых нет / пусто name_key. Обратное, name_key: '!'предназначенное для выбора любого игрока с непустым, name_keyтакже не будет работать.
Эрик Л.
Вы можете проверить этот ответ.
Илья Лузянин
4
Помните, что это работает только с массивами, а не со свойствами объекта в таком случае, какng-repeat="(key, val) in player"
Дэвид Диз
19

При реализации вы можете использовать настраиваемый фильтр ng-repeat. Что-то типа:

 data-ng-repeat="player in players |  myfilter:search.name

myfilter.js:

app.filter('myfilter', function() {


   return function( items, name) {
    var filtered = [];

    angular.forEach(items, function(item) {

      if(name == undefined || name == ''){
        filtered.push(item);
        }

      /* only if you want start With*/
      // else if(item.name_key.substring(0, name.length) !== name){
      //   filtered.push(item);
      // }

      /* if you want contains*/
      // else if(item.name_key.indexOf(name) < 0 ){
      //   filtered.push(item);
      // }

       /* if you want match full name*/
       else if(item.name_key !== name ){
        filtered.push(item);
      }
    });

    return filtered;
  };
});

Демо Plunker

Максим Шустин
источник
Спасибо за вашу работу. Это определенно правильно, но я закончил с легкостью ответа @ gion_13 в коде, поэтому решил, что лучше пометить его как принятый ответ
aron.duby