API Reference / InstantSearch iOS Widgets / Current Refinements

Current Refinements

About this widget

Current Refinements shows the currently active refinements within a given FilterState and lets users remove filters individually.

To add current refinements to your search experience, use these components:

  • CurrentFiltersInteractor: The logic for current refinements in the FilterState.
  • FilterState: The current state of the filters.
  • CurrentFiltersController: The controller that interfaces with a concrete current refinement view.
  • Presenter: Optional. The presenter that defines the way we want to display a filter.

Examples

1
2
3
4
5
6
7
8
9
10
11
let currentFiltersInteractor: CurrentFiltersInteractor = .init()
let currentFiltersController: CurrentFilterListTableController = .init(tableView: UITableView())
let filterState: FilterState = .init()

override func viewDidLoad() {
  super.viewDidLoad()

  currentFiltersInteractor.connectFilterState(filterState)
  currentFiltersInteractor.connectController(currentFiltersController)
}

Parameters

filterGroupID
type: FilterGroup.ID?
default: nil
Optional

When specified, only display current refinements matching this FilterGroupID.

1
2
3
4
let colorGroup = FilterGroup.ID.and(name: "color")

currentFiltersInteractor.connectFilterState(
  filterState, filterGroupID: colorGroup)

Presenter

Filter Presenter
type: (Filter) -> String
Optional

The presenter that defines the way we want to display a filter.

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
currentFiltersInteractor.connectController(currentFiltersController, customPresenter)

    let customPresenter: (Filter) -> String = { filter in
      let attributeName = filter.filter.attribute.name

      switch filter {
      case .facet(let facetFilter):
        switch facetFilter.value {
        case .bool:
          return filter.filter.attribute.name

        case .float(let floatValue):
          return "\(attributeName): \(floatValue)"

        case .string(let stringValue):
          return stringValue
        }

      case .numeric(let numericFilter):

        switch numericFilter.value {
        case .comparison(let comp):
          return "\(attributeName) \(comp.0) \(comp.1)"

        case .range(let range):
          return "\(attributeName): \(range.lowerBound) to \(range.upperBound)"
        }

      case .tag(let tagFilter):
        return tagFilter.value
      }
    }

Customize your view

The controllers provided by default, like the CurrentFilterListTableController work well when you want to use native UIKit with their default behavior.

If you want to use another component (other than a UITableView) such as a UICollectionView, a third-party input view, or you want to introduce some custom behavior to the already provided UIKit component, you can create your own controller conforming to the CurrentFiltersController protocol.

Protocol

func setItems(_ item: [FilterAndID]):

Function called when current filters are refreshed and need to be updated.

Note that FilterAndID is a struct that contains the filter, its ID, and the text representation of the filter

var onRemoveItem: ((FilterAndID) -> Void)?:

Closure to call when a “remove filter” intention is detected on the corresponding current filter.

func reload():

Function called when the view needs to reload itself with new data.

Example

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
open class CurrentFilterListTableController: NSObject, CurrentFiltersController, UITableViewDataSource, UITableViewDelegate {

  open var onRemoveItem: ((FilterAndID) -> Void)?

  public let tableView: UITableView

  public var items: [FilterAndID] = []

  private let cellIdentifier = "CurrentFilterListTableControllerCellID"

  public init(tableView: UITableView) {
    self.tableView = tableView
    super.init()
    tableView.dataSource = self
    tableView.delegate = self
    tableView.register(UITableViewCell.self, forCellReuseIdentifier: cellIdentifier)
  }

  open func setItems(_ item: [FilterAndID]) {
    items = item
  }

  open func reload() {
    tableView.reloadData()
  }

  // MARK: - UITableViewDataSource

  open func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return items.count
  }

  open func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath)
    let filterAndID = items[indexPath.row]
    cell.textLabel?.text = filterAndID.text

    return cell
  }

  // MARK: - UITableViewDelegate

  open func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    onRemoveItem?(items[indexPath.row])
  }

}

Did you find this page helpful?