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

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

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

У меня работает 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


person Lilalaune    schedule 26.03.2015    source источник


Ответы (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;
  };
});

Вот plunkr: http://plnkr.co/edit/xCwI2AURFpvb<6xHgYHxS?p=preview/ >

person Aliz    schedule 26.03.2015
comment
здорово, он работает именно так, как я хотел, и статья тоже полезна. Еще один вопрос: объединение этих двух фильтров - это только первый шаг к тому, что я в конечном итоге хочу создать: 4 фильтра, связанных вместе (аналогично тому, который здесь используется в Google Analytics: awesomescreenshot.com/06b4q53x83 filter1: включить / исключить filter2: выбрать столбец (как здесь решено) filter3: различные параметры фильтра (включить, начать с, равно и т. Д.) Filter4 : поле ввода (как здесь решено), которое вы по-прежнему рекомендовали бы определять функции или лучше использовать настраиваемые фильтры? - person Lilalaune; 26.03.2015
comment
Не могли бы вы дать мне приблизительное количество отображаемых строк? 100? 500? 1000? более ? - person Aliz; 26.03.2015
comment
конечно - от 700 до 1000 - person Lilalaune; 26.03.2015
comment
Будете ли вы повторно использовать эти фильтры на других страницах? (по отдельности или комбинация) Если ответ положительный, то я рекомендую вам использовать фильтры. - person Aliz; 26.03.2015
comment
он будет использоваться в одном основном представлении, но может потребоваться менее сложная версия на другой странице. Так что, думаю, мне лучше использовать фильтры. Как я мог переписать указанную выше функцию в фильтр, выполняющий то же самое? Я новичок в angular, и небольшая помощь будет очень признательна - person Lilalaune; 26.03.2015
comment
Пожалуйста, проверьте ссылку plunk, я обновил код, чтобы использовать фильтр, я добавил секунду, чтобы вы могли увидеть, как можно использовать другой фильтр. (видно только на plunkr) - person Aliz; 26.03.2015
comment
Большое спасибо за вашу помощь - хотел бы я снова проголосовать за это. проверил плункер, но последняя версия (25) похоже не работает (таблица данных почти пуста) - person Lilalaune; 26.03.2015
comment
Это потому, что я связал 2 фильтра :), это было показать вам, как связать 2 фильтра - person Aliz; 26.03.2015

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

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

person gsalisi    schedule 26.03.2015
comment
Спасибо за это - я новичок в angular и не знаю, как перенести этот пример в свой случай. не могли бы вы указать мне в правильном направлении? - person Lilalaune; 26.03.2015

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

.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"

Это плункер.

person yazaki    schedule 26.03.2015
comment
спасибо за это - я попробовал ваш плункер, но searchFilter не работает - есть идеи, как это исправить? - person Lilalaune; 26.03.2015
comment
Чтобы сделать образец как можно более простым, я использую Array.filter для реализации функции фильтрации. Если вы используете старый браузер, который не поддерживает Array.filter, этот образец не будет работать нормально. Мой Chrome (и Firefox) может работать нормально. Конечно, вам нужно немного изменить, чтобы поддерживать старые браузеры. - person yazaki; 26.03.2015
comment
Кстати, это новая версия образца, которая использует underscore.js для поддержки старого браузера. Мой IE9 работает нормально. - person yazaki; 26.03.2015