EloquentStudio / filter.js

Complete solution for client side filtering and rendering using JSON data
http://eloquentstudio.github.io/filter.js
MIT License
665 stars 183 forks source link

Filter.js

CDNJS version Open Source Helpers

Filter.js is client-side JSON objects filter which can render html elements. Multiple filter criteria can be specified and used in conjunction with each other.

Usage

Basic requirement to implement filtering using filter.js are JSON data, a 'View' template and a filter criteria.

Filter Initialisation

It takes three arguments one is movies, second is 'container' in which html elements are to be to appended and the third one is options. You can set options such as template, criteria, callbacks and search but only template is compulsory.

var FJS = FilterJS(movies, '#movies', {
  template: '#movie-template',
  filter_on_init: true, // Default filter_on_init is false
  callbacks: {
    afterFilter: function(result){
      $('#total_movies').text(result.length);
     }
   }
});

To append each item in different container use option appendToContainer. This option is a function with two arguments, one is html element content and second is record object.


//This will append elements to specific year.
var appendFn = function(html_ele, record) {
  $("#" + record.year).append(html_ele);
}

var FJS = FilterJS(movies, '#movies', {
  template: '#movie-template',
  appendToContainer: appendFn
});

JSON data

Capture the JSON data (maybe using @movies.to_json).

  var movies = [
  {
    "name": "The Shawshank Redemption",
    "rating": 9.3,
    "director": "Frank Darabont",
    "year": 1994,
    "stars": [
      "Tim Robbins",
      "Morgan Freeman",
      "Bob Gunton"
    ],
    "runtime": 142,
    "genre": [
      "Crime",
      "Drama"
    ],
    "id": 1
  },
  ....
  ....
 ]

View

Rendering JSON objects requires a view template. The micro-templating module in filter.js is inspired by Underscore.js.

    <script id="movie-template" type="text/html">
      <div class="movie">
        <div class="thumbnail">
          <span class="label label-success rating"><%= rating %></span>
          <div class="caption">
            <h4><%= name %></h4>
            <div class="outline">
              <%= outline %>
              <span class="runtime">
                <i class="glyphicon glyphicon-time"></i>
                <%= runtime %> mins.
              </span>
            </div>
            <div class="detail">
              <dl>
                <dt>Actors</dt>
                <dd><%= stars %></dt>
                <dt>Year</dt>
                <dd><%= year %></dd>
              </dl>
            </div>
          </div>
         </div>
       </div>
    </script>

Filter Criteria

The two mandatory options required are field which is name of any property from JSON data and other is HTML ele element on which filter will be triggered by an event(e.g. click, change, etc.). Other filter options are type, event and selector.

There are two way to add criteria. One is add at time of filter object initialisation and other is add when required.

  //On create
  var fjs = FilterJS(movies, '#movies', {
    template: '#movie-template',
    criterias: [ {field: 'year', ele: '#year_filter', type: 'range'} ]
  }

  // Add one at a time.
  FJS.addCriteria({field: 'year', ele: '#year_filter', type: 'range'})
  FJS.addCriteria({field: 'genre', ele: '#genre_criteria input:checkbox'})

  // with all  option
  FJS.addCriteria({field: 'year', ele: '#year_filter', type: 'range', all: 'all_years'})

  // Full options list.
  FJS.addCriteria({field: 'genre', ele: '.genres', event: 'change', selector: ':checked' })

field: genre this is a JSON attribute defined in JSON objects.

For Range selections

More detail for range filter. It is expected to set ranges as values like '20-30'

Example:

<input checked="checked" value="20-30" type="checkbox">

For nested field selection: In the below object, to select filter on name field option value would be detail.name and for city detail.address.city.

JSON object:

    {
      detail: { name: 'Jiren', address: { city: 'Pune' } }
    }

Remove criteria.

Using removeCriteria, remove criteria dynamically. It take one argument filed name. i.e removing year criteria.

fjs.removeCriteria('year')

Filtering Callbacks

Define callback in settings. Callbacks execute on different events.

i.e.,

  var filter_callbacks = {
    beforeAddRecords: function(records){
      // Process new JSON data records.
      // i.e Process data before adding to filter while streaming.
    },
    afterAddRecords: function(records){
      // i.e Update google markers or update sorting.
    },
    beforeRender: function(records){
     //
    },
    beforeRecordRender: function(record){
      //i.e Add/Update record fields
    },
    afterFilter: function(result){
      // i.e Update result counter, update google map markers.
    }
  };

Init Filter object with above callbacks

var fjs = FilterJS(movies, '#movies', {
  template: '#movie-template',
    callbacks: filter_callbacks
  }

  # Or add callback separately.
  FJS.addCallback('afterAddRecords', function(){
    // i.e Update total count
  });

Instant Search integration

To enable search, add a textbox element and set the selector in options. By default search will work on all JSON object fields. If you want to search on some particular fields then set the fields option.

  // Init with search
  FilterJS(movies, '#movies', {
    template: '#movie-template',
    search: { ele: '#searchbox' }  // Search in all fields of JSON object.
  }

  // Search in given fields
  search: { ele: '#searchbox', fields: ['name', 'runtime'] }

The search will trigger after 2 characters by default. This can be configured using start_length option.

  search: {ele: '#searchbox', fields: ['name', 'runtime'], start_length: 4 }

By default search will start immediately after a user types. A timeout can be configured using timeout option (in milliseconds).

  search: {ele: '#searchbox', fields: ['name', 'runtime'], timeout: 100 }

Add more data to existing filter

If you are streaming JSON data using ajax then you can add data like this

var fjs = FilterJS(movies, '#movies', { template: '#movie-template'})

fJS.addData(data)

Add data using ajax streaming

Add streaming option to above define 'settings'.

  var fjs = FilterJS(movies, '#movies', {
    template: '#movie-template',
    streaming: {
      data_url: 'movies/index.json',
      stream_after: 1,
        batch_size: 50
      }
  });
movies/index.json.json?offset=0&limit=50&q='search text'

Add streaming after initialisation.

fjs.setStreaming({
  data_url: 'data/stream_movies.json',
  stream_after: 1,
  batch_size: 50
});

Remove records from filtering

fjs.removeRecords([1,2,3]);
  fjs.removeRecords({year: 1980});

  fjs.removeRecords({'year.$gt': 1980, 'rating': 8.5});

Change Template dynamically and Rebuild

If you want to change the template dynamically but do not want to re-render the view (you many choose to render the template yourself) then just pass the template name to setTemplate function.

  fjs.setTemplate('#movie-list-template');

If you want to re-render the new template then pass a second paramater as true. This will render the container with the data using the new template specified and apply the filtering.

  fjs.setTemplate('#movie-list-template', true);

Build and Development

Note

Demo

To see the sample demo, clone this repo and open demo/filterjs.html in your browser

Filter

Auto filtering using html attributes

Filter - Google Map

Filter with Pagination

Used by

Statistisches Amt Basel-Stadt

Mianillo

Itrenewdirect (product search)

Tischefrei (search page)

Roboty przemysłowe

Byte b.v. (partner page)

Belihewan

If you use this, please send me an email, I shall add your link here!

Sponsors and Supporters

Contributing

Please send me a pull request so that this can be improved.

License

This is released under the MIT license.