summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/filterable_list.js
blob: 9e91f72b2ea5ad4b5338eced9803ce2f11d7a634 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
import _ from 'underscore';

/**
 * Makes search request for content when user types a value in the search input.
 * Updates the html content of the page with the received one.
 */

export default class FilterableList {
  constructor(form, filter, holder, filterInputField = 'filter_groups') {
    this.filterForm = form;
    this.listFilterElement = filter;
    this.listHolderElement = holder;
    this.filterInputField = filterInputField;
    this.isBusy = false;
  }

  getFilterEndpoint() {
    return `${this.filterForm.getAttribute('action')}?${$(this.filterForm).serialize()}`;
  }

  getPagePath() {
    return this.getFilterEndpoint();
  }

  initSearch() {
    // Wrap to prevent passing event arguments to .filterResults;
    this.debounceFilter = _.debounce(this.onFilterInput.bind(this), 500);

    this.unbindEvents();
    this.bindEvents();
  }

  onFilterInput() {
    const $form = $(this.filterForm);
    const queryData = {};
    const filterGroupsParam = $form.find(`[name="${this.filterInputField}"]`).val();

    if (filterGroupsParam) {
      queryData[this.filterInputField] = filterGroupsParam;
    }

    this.filterResults(queryData);

    if (this.setDefaultFilterOption) {
      this.setDefaultFilterOption();
    }
  }

  bindEvents() {
    this.listFilterElement.addEventListener('input', this.debounceFilter);
  }

  unbindEvents() {
    this.listFilterElement.removeEventListener('input', this.debounceFilter);
  }

  filterResults(queryData) {
    if (this.isBusy) {
      return false;
    }

    $(this.listHolderElement).fadeTo(250, 0.5);

    return $.ajax({
      url: this.getFilterEndpoint(),
      data: queryData,
      type: 'GET',
      dataType: 'json',
      context: this,
      complete: this.onFilterComplete,
      beforeSend: () => {
        this.isBusy = true;
      },
      success: (response, textStatus, xhr) => {
        this.onFilterSuccess(response, xhr, queryData);
      },
    });
  }

  onFilterSuccess(response, xhr, queryData) {
    if (response.html) {
      this.listHolderElement.innerHTML = response.html;
    }

    // Change url so if user reload a page - search results are saved
    const currentPath = this.getPagePath(queryData);

    return window.history.replaceState({
      page: currentPath,
    }, document.title, currentPath);
  }

  onFilterComplete() {
    this.isBusy = false;
    $(this.listHolderElement).fadeTo(250, 1);
  }
}