Angularjs: фильтрация ng-repeat с помощью ng-if - PullRequest
0 голосов
/ 24 июня 2019

Наша команда создает виджет в ServiceNow, который отображает плитки задач для пользователя. Наш код выглядит так:

  <ul class="card-list" ng-init="init(user.sys_id)">
    <li class="card-list-item" ng-repeat="task in data.tasks | orderBy: ['due_date']" ng-if="!task.finished">
      <div class="card" ng-click="task.finished ||c.onWidget(task)" ng-style="taskBorderColor(task)">
        <div class="card-image flex justify-content-center">
          <i ng-if="!task.finished && task.isOverDue" class="{{task.icon}} fa-5x" style="color:{{c.options.overdue_color}}" aria-hidden="true" alt="overdue"></i>
          <i ng-if="!task.finished && !task.isOverDue" class="{{task.icon}} fa-5x" style="color:{{c.options.pending_color}}" aria-hidden="true" alt="pending"></i>
          <i ng-if="!task.finished && task.isOptional" class="{{task.icon}} fa-5x" style="color:{{c.options.optional_color}}" aria-hidden="true" alt="optional"></i>
          <i ng-if="task.finished" class="{{task.icon}} fa-5x" aria-hidden="true" style="color:{{c.options.finished_color}}" alt="completed"></i>
        </div>
        <div class="card-content text-center">
          <h4 class="card-heading">
            <a ng-click="">{{::task.short_description}}</a>
          </h4>
          <span class="text-normal m-b-sm">${For:} {{::task.assigned_to_name}} <!--{{::task.taskInfo.subject_person}}--></span>
          <span ng-if="!task.finished" class="m-b-sm">
            <span class="text-normal" ng-if="task.due_date">${Due by} {{::task.due_date | date: 'mediumDate' }}
          </span>
          <!-- Added in Completed Date when task is finished -->
          <span ng-if="task.finished" class="m-b-sm">
            <span class="text-normal" ng-if="task.closed_at">${Completed at} {{::task.closed_at | date: 'mediumDate' }}
            </span>
          </span>
        </div>
        <div class="status" ng-style="taskStatusStyle(task)">
          <div class="text-center text-uppercase" ng-if="!task.finished && task.isOverDue">Overdue</div>
          <div class="text-center text-uppercase" ng-if="!task.finished && !task.isOverDue">In Progress</div>
          <div class="text-center text-uppercase" ng-if="!task.finished && task.isOptional">Optional</div>
          <div class="text-center text-uppercase" ng-if="task.finished">Completed</div>
        </div>
      </div>
    </li>
  </ul>

В приведенном выше коде у нас есть ng-if в строке 2 с тегом <li>, который показывает только задачи, которые не были выполнены (ng-if=!task.finished). Тем не менее, мы хотим дать пользователю возможность показывать законченные задачи или нет. Мы создали логический элемент схемы параметров с именем show_completed_items. Если show_completed_items отмечен как true, мы хотим убрать ng-if="!task.finished", чтобы отображались ВСЕ задачи.

Мы пробовали что-то подобное, наряду с некоторыми другими вариантами этого без удачи:

ng-if="!c.options.show_completed_items ? !task.finished : (!task.finished || task.finished)"

Спасибо за любую помощь!

1 Ответ

1 голос
/ 24 июня 2019

Это упрощенная демонстрация, показывающая, что ответ Лекса на самом деле правильный: https://stackblitz.com/edit/angularjs-p7bqma?file=home/home.html

Шаблон:

<label for="show-finished-checkbox">Show Finished</label>
<input id="show-finished-checkbox" type="checkbox" ng-model="$ctrl.showFinished">

<ul>
  <li ng-repeat="item in $ctrl.items" ng-if="!item.finished || $ctrl.showFinished">{{item.name}} / Finished: {{item.finished}}</li>
</ul>

Контроллер:

class HomeCtrl {
  constructor($scope) {
    'ngInject';

    this.items = [
      {
        name: "Item 1",
        finished: false
      },
      {
        name: "Item 2",
        finished: true
      },
      {
        name: "Item 3",
        finished: false
      }
    ]
  }
}

export default HomeCtrl;

Другой подход заключается в использовании пользовательского фильтра. Это особенно хорошо для сушки шаблона и фильтрации в более сложных условиях:

Шаблон:

<ul>
  <li ng-repeat="item in $ctrl.items | finished: $ctrl.showFinished" >{{item.name}} / Finished: {{item.finished}}</li>
</ul>

JS код:

window.app.filter('finished', function() {
  return function(input, showFinished) {
    var out = [];
    angular.forEach(input, function(item) {

      if(!item.finished || showFinished) {
        out.push(item);
      }
    })
    return out;
  }
})
...