Угловые фильтры: как предварительно отфильтровать так, чтобы угловые фильтры рассматривали только часть всего объекта данных


Я получил большую таблицу данных (которая получает свои данные из JSON api) с несколькими столбцами и хотел бы реализовать несколько фильтров, делая следующее:

  1. Возможность выбрать, какой столбец данных следует рассматривать (раскрывающийся список, содержащий опцию thead) [my columnFilter] и тогда
  2. поле ввода для фильтрации конкретных данных-partial [my searchFilter]

У меня работает поисковый фильтр, но я не знаю, как подключить columnFilter и сделать searchFilter применяется только к выбранным данным-частичным.

Итак, предположим, что я хотел бы видеть только описания, содержащие мир "синий".

Как я могу связать эти два фильтра и заставить их работать?

Вот некоторые из моих кодов:

  Select data column:
  <select ng-model="columnFilter" ng-options="heading for heading in headings">
  </select>
</div>
<div class="col-sm-12">
   Filter selection: <input type='text' ng-model="searchFilter" />
</div>
<table class="table table-bordered">
    <thead>
      <tr>
        <th>URL</th>
        <th>Title</th>
        <th>Traffic</th>
        <th>Description</th>
        <th>ID</th>
      </tr>
  </thead>
  <tbody ng-repeat="url in urls | filter:searchFilter">
    <tr>
      <td>{{url.url}}</td>
      <td>{{url.title}}</td>
      <td>{{url.traffic}}</td>
      <td>{{url.descr}}</td>
      <td>{{url.id}}</td>
    </tr>
    </tbody>
</table>

И ссылка на рабочий поршень: http://plnkr.co/edit/TddllGiey0RmCx18eVdd?p=preview

3 3

3 ответа:

Насколько я знаю angular, есть два основных способа решить вашу проблему.

  1. определите пользовательский фильтр
  2. определите функцию для фильтрации данных и вызовите ее с помощью ng-show или ng-hide

Я получил большую таблицу данных

Если я хорошо понимаю, вы указываете это, потому что производительность-это большая проблема.

Есть хорошая статья, которая раскрывает различия между этими двумя решениями. : http://www.bennadel.com/blog/2487-filter-vs-nghide-with-ngrepeat-in-angularjs.htm

Поскольку производительность может быть действительно важна для вас, я предлагаю вам второй подход.

На ваш взгляд:

<tbody ng-repeat="url in urls" ng-show="filterUrl(url)">

В вашем контроллере:

$scope.searchFilter = "";
$scope.columnFilter = $scope.headings[5];

$scope.filterUrl = function(url){ 
  if(!$scope.searchFilter || $scope.searchFilter == "")
    return url;
  var searchFilter= $scope.searchFilter.toLowerCase();
  var trafficString = url.traffic.toString();
  var idString = url.traffic.toString();
  switch($scope.columnFilter){
    case $scope.headings[0]:
      return url.title.toLowerCase().indexOf(searchFilter) != -1;
    case $scope.headings[1]:
      return url.url.toLowerCase().indexOf(searchFilter) != -1;
    case $scope.headings[2]:
      return trafficString.indexOf(searchFilter) != -1;
    case $scope.headings[3]:
      return url.descr.toLowerCase().indexOf(searchFilter) != -1;
    case $scope.headings[4]:
      return idString.indexOf(searchFilter) != -1;
    case $scope.headings[5]: 
      return url.title.toLowerCase().indexOf(searchFilter) != -1 ||
      url.url.toLowerCase().indexOf(searchFilter) != -1 ||
      trafficString.indexOf(searchFilter) != -1 ||
      url.descr.toLowerCase().indexOf(searchFilter) != -1 ||
      idString.indexOf(searchFilter) != -1;
  }
};

Обновление: Если вы выберете первый подход:

На ваш взгляд:

 <tbody ng-repeat="url in urls | filterByColumn: searchFilter :columnFilter">

Фильтр:

app.filter('filterByColumn', function(){
  return function(urls, text, columnFilter){
    var processed = [];
     if(!text || text == "")
        return urls;
    urls.forEach(function(url){
      var searchFilter= text.toLowerCase();
      var trafficString = url.traffic.toString();
      var idString = url.traffic.toString();
      switch(columnFilter){
        case "Title":
          if( url.title.toLowerCase().indexOf(searchFilter) != -1)
            processed.push(url);
          break;
        case "Url":
          if(url.url.toLowerCase().indexOf(searchFilter) != -1)
            processed.push(url);
          break;
        case "Traffic":
          if(trafficString.indexOf(searchFilter) != -1)
            processed.push(url);
          break;
        case "Description":
          if(url.descr.toLowerCase().indexOf(searchFilter) != -1)
            processed.push(url);
          break;
        case "Id":
          if( idString.indexOf(searchFilter) != -1)
            processed.push(url);
          break;
        case "All": 
          if( url.title.toLowerCase().indexOf(searchFilter) != -1 ||
          url.url.toLowerCase().indexOf(searchFilter) != -1 ||
          trafficString.indexOf(searchFilter) != -1 ||
          url.descr.toLowerCase().indexOf(searchFilter) != -1 ||
          idString.indexOf(searchFilter) != -1)
            processed.push(url);
          break;
      }
    });
    return processed;
  };
});

Вот планкр: http://plnkr.co/edit/xCwI2AURFpvb6xHgYHxS?p=preview

Проверьте, как этот пример прямо с угловой страницы создания пользовательского фильтра. https://docs.angularjs.org/guide/filter

Здесь вы можете увидеть, что вы можете создать фильтр, который принимает 2 входных сигнала, фактический объект и параметр. Передавая имя столбца в качестве параметра, вы можете сузить поиск правильных строк.

Я бы рекомендовал вам написать простой пользовательский фильтр, подобный этому.

.filter('myfilter', function(){
  return function(input, column, text){
    if (!input || !column || !text) return input;
    return input.filter(function(item){
      var value = item[column.toLowerCase()];
      if (!value)return false;
      return value.indexOf(text)>-1;
    });
  };
});

Вы можете использовать этот фильтр в html.

ng-repeat="url in urls | myfilter:columnFilter:searchFilter"

Это планкер.