0

I've done filtering numerous times before, but am having trouble with this specific case. I have a list of objects set up in pagination, but I also want to be able to filter them for ease of use. An example object might look like:

{
    baseline:0.75
    clonedFrom:Object
    description:"Just a simple description.."
    includeable:false
    key:"bc889881-7979-4e04-b586-d53faab26b6b"
    name:"Just a simple question?"
    type:"BayesianModel"
    version:1483477351992
    versionComment:null
    versionLabel:"0.11"
}

For the most part, what the object looks like is arbitrary, I just included it for ease of answering. I am trying to filter on both the name and description of the object at the same time. For example if the user knew a key word in either they could narrow down the results.

I have the input for the filter and the results inside of a <ul> shown below:

<ul class="list-group">
  <li class="list-group-item">
    <div class="form-group has-feedback">
      <input type="text"
          ng-model="vm.resultFilter"
          ng-change="vm.updateFilter()"
          class="form-control filterInput"
          placeholder="Filter Results" />
      <span ng-if="vm.resultFilter"
          ng-click="vm.resultFilter = ''; vm.updateFilter();"
          class="fa fa-times fa-lg form-control-feedback">
      </span>
    </div>
  </li>
  <li class="list-group-item link-row model-list"
      ng-repeat="result in vm.filteredResults
          | startFrom : ((vm.currentPage - 1) * vm.itemsPerPage)
          | limitTo: vm.itemsPerPage"
      ng-if="result.name != vm.model.name"
      ng-click="vm.selected = result;"
      ng-class="{selected: result === vm.selected}"
      ng-init="displayNumber = vm.incrementDisplayIndex();">
    <h4 class="list-group-item-heading">{{result.description}} - {{result.name !== vm.model.name}}</h4>
    <p class="list-group-item-text">
      {{result.name}}
    </p>
  </li>
</ul>

So the name of the filter is vm.resultFilter and the cooresponding method that is called every time the filter is updated is updateFilter() (which is necessary for the pagination stuff).

function updateFilter() {
  vm.filteredResults = $filter('filter')(vm.results, {
    'name': vm.resultFilter,
    'description': vm.resultFilter
  });
  vm.totalItems = vm.filteredResults.length;
  vm.noOfPages = Math.ceil(vm.filteredResults.length / vm.itemsPerPage);
}

I am just having trouble with getting the filtering to work 100%. Sometimes it appears it's only filtering on the description field, but then sometimes I will search a word that is in the description field of only one result and it will filter with no results (which would be false). Any tips appreciated.

erp
  • 2,950
  • 9
  • 45
  • 90
  • Take into account that your filter works with and AND operator. It means, that a result must match both conditions name and description to be a result. – Manu Obre Jan 09 '17 at 13:08
  • I understand what you mean, but I am not using an `AND` operator anywhere? Unless, by pointing both fields to `vm.resultFilter` that is what is happening. If that is the case, how then do I make that an `OR` operator? – erp Jan 09 '17 at 13:13
  • Pointing both fields, makes the filter to work under the AND condition. This might be helpful http://stackoverflow.com/questions/15868248/how-to-filter-multiple-values-or-operation-in-angularjs – Manu Obre Jan 09 '17 at 13:22
  • I appreciate the link. I had already looked @ that, and the result of that problem is only filtering on one field of the object. It's just whether or not it equals `family` or `action` which both reside under the `genre` field of the object. I am trying to `OR` two different fields I guess. – erp Jan 09 '17 at 13:31

1 Answers1

1

Since your are not using the filter inside your HTML, I recommend you to use the filter property from the Array prototype.

function updateFilter() {
  vm.filteredResults = vm.results.filter(function(item){
    return (item.name==vm.resultFilter || item.description==vm.resultFilter )
  }

  vm.totalItems = vm.filteredResults.length;
  vm.noOfPages = Math.ceil(vm.filteredResults.length / vm.itemsPerPage);
}

In case you need to determines whether a string contains the characters of a specified string. You might need to use includes instead of ==

vm.filteredResults = vm.results.filter(function(item){
   return (item.name.includes(vm.resultFilter) || item.description.includes(vm.resultFilter) )
}
Manu Obre
  • 2,254
  • 1
  • 12
  • 12
  • Great. So the second one is more of what I am looking for. Just a curious question if you know off the top of your head: Do you know how to make the filtering in this case non case sensitive? Angular by default is, though in this case since it is 'does it include the string' obviously it's going to be case sensitive (which for me is undesirable) – erp Jan 09 '17 at 13:50
  • transform both string to lower-case with the String property .toLowerCase() item.name.toLowerCase().includes(vm.resultFilter.toLowerCase()) – Manu Obre Jan 09 '17 at 13:58
  • okay cool, yea that was the obvious solution ;) but just seeing if I had other options. thanks for the help today m8 – erp Jan 09 '17 at 14:18
  • anytime, as far as I know, you do not have an option to set that. – Manu Obre Jan 09 '17 at 14:21