jimmypage
jimmypage

Reputation: 666

Backbone filter a collection using multiple attributes

I am new to backbone js. I am trying to create an application that displays certain data and allows users to filter them with certain attributes and narrow down results. My fetched data has three fields : Organisation name, Organisation type and Country. Users can apply filter on Organisation type and Country by selecting them from drop down list. The Organisation type and Country could be multiple. I used jQuery's select2 to allow users to select multiple organisation types and countries. The Organisation name is filtered on each keystroke on the input field. I managed to create a filter that filters the record based on all three attributes separately. Here's my collection along with my filter function:

var OrganisationCollection = Backbone.PageableCollection.extend({
  model: Organisation,
  state: {pageSize: 20},
  mode: "client",
  queryParams: {
    currentPage: "current_page",
    pageSize: "page_size"
  },

  filterBy: function(organisationName, organisationType, countryName){
    var matchingModels;
    var filterFunction = function(model) {
      var check = (model.get('name').indexOf(organisationName)>-1);
      return check;
    }
    collectionToFilter = this;
    matchingModels = filteredCollection(collectionToFilter, filterFunction);

    function filteredCollection(original, filterFn) {
      var filtered;
      // Instantiate new collection
      filtered = new original.constructor();
      // Remove events associated with original
      filtered._callbacks = {};
      filtered.filterItems = function(filter) {
        var items;
        items = original.filter(filter);
        filtered._currentFilter = filterFn;
        return filtered.reset(items);
      };
      // Refilter when original collection is modified
      original.on('reset change destroy', function() {
        return filtered.filterItems(filtered._currentFilter);
      });
      return filtered.filterItems(filterFn);
    };
    collectionToFilter = new OrganisationCollection(matchingModels);
    return collectionToFilter;
  }
});

Now, this filter function only filters the collection based on organisation name. If I were to filter my collection based on organisation type, my filterBy function would be:

filterBy: function(organisationName, organisationType, countryName){
  var matchingModels;
  var filterFunction = function(model) {
    var check = typeof organisationType=='string' ?  (model.get('type').indexOf(organisationType)>-1) : (_.indexOf(organisationType, model.get('type')) > -1);
    return check;
  }
  collectionToFilter = this;
  matchingModels = filteredCollection(collectionToFilter, filterFunction); // filterFunction would be same as above
  collectionToFilter = new OrganisationCollection(matchingModels);
  return collectionToFilter;
}

My filterBy country function would be similar to above. Now my problem is that these three functions work fine separately. But I am unable to merge these three functions to narrow down the results. i.e. when a user filters with countries USA and Australia, types corporate and multilateral, only those organisations from countries USA and Australia having types corporate and multilateral are supposed to show. And again, among those results, if the user types 'A' in Organisation name input field, only those organisations from previous results starting with alphabet 'A' are supposed to show. I have no idea how to implement that. Here's my function that triggers the filter:

$(document).ready(function(){
  var country = $("#filter-country").val();
  var countryName = country ? country : '';
  var type = $("#filter-org-type").val();
  var orgType = type ? type : '';
  var orgName = '';

  $("#filter").on('input',function(e){
    var orgFilter = $('#filter').val();
    orgName = orgFilter ? orgFilter : '';
    orgCollection.trigger("filter-by-organisation",orgName, orgType, countryName);
  });
// Users can select countries from select field #filter-country and types from select field #filter-org-type and click on button #apply-filters to trigger filter function
  $(document).on('click', '#apply-filters', function(){
    orgCollection.trigger("filter-by-organisation",orgName, orgType, countryName);
  });
});

Please help me with this. Thanks

Upvotes: 0

Views: 464

Answers (1)

T J
T J

Reputation: 43156

I might not have understood your problem very well, but you could simply do something like this:

var OrganisationCollection = Backbone.PageableCollection.extend({
  model: Organisation,
  filterBy: function(organisationName, organisationType, countryName) {
    var organisationNameResults = this.filter(function(model) {
      // your logic for filtering based on organisationName
    });
    var organisationTypenResults = _.filter(organisationNameResults, function(model) {
      // your logic for filtering based on organisationType
    });
    var countryNameResults = _.filter(organisationTypenResults, function(model) {
      // your logic for filtering based on countryName
    });
    this.reset(countryNameResults);
  }
});

It can be refactored, this is just to give you an idea

Upvotes: 0

Related Questions