UI libraries / InstantSearch iOS / Widgets
Signature
# <!-- vale off -->
# The actual component name is `interactor`, so the linting rule is ignored here
RelevantSortConnector<Controller: RelevantSortController, Output>(
  searcher: SingleIndexSearcher,
  interactor: RelevantSortInteractor,
  controller: Controller,
  presenter: RelevantSortPresenter<Output>
)

RelevantSortConnector<Controller: RelevantSortController, Output>(
  searcher: SingleIndexSearcher,
  interactor: RelevantSortInteractor,
  controller: Controller,
  presenter: RelevantSortTextualPresenter
)
# <!-- vale on -->

About this widget

Virtual indices allow you to use Relevant sort, a sorting mechanism that favors relevancy over the attribute you’re sorting on. The relevantSort widget displays the current search mode when searching in a virtual replica index, and allows users to switch between relevant and regular sorting, which is more exhaustive and can return less relevant results.

Examples

Instantiate a RelevantSortConnector.

1
2
3
4
5
let searcher = HitsSearcher(appID: "YourApplicationID",
                            apiKey: "YourSearchOnlyAPIKey",
                            indexName: "virtual_replica_index")
let relevantSortController: ButtonRelevantSortController = .init()
let relevantSortConnector: RelevantSortConnector = .init(searcher: searcher, controller: relevantSortController)

Parameters

Parameter Description
searcher
type: HitsSearcher
Required

The Searcher that handles your searches.

interactor
type: RelevantSortInteractor
default: .init()
Required

The logic to toggle Relevant Sort.

controller
type: RelevantSortController
default: nil
Optional

Controller that presents and can toggle the Relevant Sort priority state.

presenter
type: RelevantSortPresenter<Output> | RelevantSortTextualPresenter
default: DefaultPresenter.RelevantSort.present
Required

Presenter transforming the Relevant sort priority state to its representation for a controller.

Presenter

Parameter Description
RelevantSort Presenter
type: RelevantSortPresenter<Output> | RelevantSortTextualPresenter
default: DefaultPresenter.RelevantSort.present
Required

Presenter transforming the Relevant sort priority state to its representation for a controller. Default presenter transforms Relevant sort priority to ‘RelevantSortTextualRepresentation?’ providing a tuple of string constants in english.

1
2
3
4
5
6
7
8
9
10
public static func present(_ priority: RelevantSortPriority?) -> RelevantSortTextualRepresentation? {
    switch priority {
    case .some(.hitsCount):
      return ("Currently showing all results.", "Show more relevant results")
    case .some(.relevancy):
      return ("We removed some search results to show you the most relevants ones.", "Show all results")
    default:
      return nil
    }
  }

Low-level API

If you want to fully control the RelevantSort components and connect them manually, you can use the following components:

  • Searcher: The Searcher that handles your searches.
  • RelevantSortInteractor: Relevant sort priority toggling logic.
  • RelevantSortController: the controller that presents and toggles the Relevant sort priority state.
  • RelevantSortPresenter<Output>: optional. Generic presenter transforming the Relevant Sort priority state to its representation for a controller.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
let searcher = HitsSearcher(appID: "YourApplicationID",
                            apiKey: "YourSearchOnlyAPIKey",
                            indexName: "virtual_replica_index")

let relevantSortInteractor = RelevantSortInteractor()
let relevantSortController: ButtonRelevantSortController = .init()

relevantSortInteractor.connectSearcher(searcher)

let relevantSortpresenter: RelevantSortTextualPresenter = { priority in
  switch priority {
  case .some(.hitsCount):
    return ("Currently showing all results.", "Show more relevant results")
  case .some(.relevancy):
    return ("We removed some search results to show you the most relevants ones.", "Show all results")
  default:
    return nil
  }
}

relevantSortInteractor.connectController(relevantSortController, presenter: relevantSortpresenter)

Customizing your view

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

If you want to use another component, 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 RelevantSortController protocol.

Protocol

func setItem(_ item: RelevantSortTextualRepresentation?)

Function called when a new array of indices is defined.

var didToggle: (() -> Void)? { get set }

Closure triggered by the controller when the toggle happens (for example, toggle button clicked or switch control state changed)

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
public class RelevantSortControl: NSObject, RelevantSortController {

  public let hintLabel: UILabel
  public let toggleButton: UIButton

  public var didToggle: (() -> Void)?

  public init() {
    hintLabel = .init()
    toggleButton = .init()
    super.init()
    toggleButton.addTarget(self, action: #selector(didTapToggleButton), for: .touchUpInside)
  }

  public func setItem(_ item: RelevantSortTextualRepresentation?) {
    hintLabel.isHidden = item == nil
    toggleButton.isHidden = item == nil
    hintLabel.text = item?.hintText
    toggleButton.setTitle(item?.toggleTitle, for: .normal)
  }

  @objc func didTapToggleButton() {
    didToggle?()
  }

}

SwiftUI

InstantSearch provides the RelevantSortObservableController data model, which is an implementation of the RelevantSortController protocol adapted for usage with SwiftUI. RelevantSortObservableController must be connected to the RelevantSortConnector or RelevantSortInteractor like any other RelevantSortController implementation.

The example of the SwiftUI view presenting the relevant sort state.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
  struct ContentView: View {
  
  @ObservedObject var relevantSortController: RelevantSortObservableController
      
  var body: some View {
    VStack {
      if let state = relevantSortController.state {
        HStack {
          Text(state.hintText)
          Spacer()
          Button(state.toggleTitle,
                 action: relevantSortController.toggle)
        }
      }
    }
  }

}

If you prefer to create a custom SwiftUI view that presents the list of facets, you can directly use the RelevantSortObservableController as a data model. It provides the state property along with the toggle function to streamline the design process of your custom SwiftUI view.

Did you find this page helpful?