Concepts / Building Search UI / Query suggestions
May. 10, 2019

Query Suggestions

Overview

When your user interacts with a SearchBox, you can help them discover what they could search for by providing Query suggestions.

This is a specific kind of multi-index interface: your main search interface will be using a regular index, while you will display suggestions as the user types from your Query Suggestions index.

To display the suggestions in your iOS app, you can do it by using the power of viewModels with our MultiHitsViewModel component. See below for a full example on how to display a search bar with a tableView with 2 sections, the first one containing the query suggestions and the second one containing the instant results.

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
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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
import UIKit
import InstantSearch
import AFNetworking

class QuerySuggestionDemo: UIViewController, UITableViewDataSource, UITableViewDelegate, UISearchBarDelegate {
    
    @IBOutlet weak var tableView: MultiHitsTableWidget!
    @IBOutlet weak var searchBar: SearchBarWidget!
    
    var multiHitsViewModel: MultiHitsViewModel!
    var searchViewModel: SearchViewModel!
    
    var isTextBarClicked = false
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        multiHitsViewModel = MultiHitsViewModel(view: tableView)
        InstantSearch.shared.register(viewModel: multiHitsViewModel)
        searchViewModel = SearchViewModel(view: searchBar)
        InstantSearch.shared.register(viewModel: searchViewModel)
        InstantSearch.shared.search()
        
        searchBar.placeholder = "Search a pro..."
        
        searchBar.delegate = self
        tableView.dataSource = self
        tableView.delegate = self
    }
    
    func numberOfSections(in tableView: UITableView) -> Int {
        return multiHitsViewModel.numberOfSections()
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        if section == 0 && !isTextBarClicked { // Show query suggestion on when textbar is clicked
            return 0
        }
        
        return multiHitsViewModel.numberOfRows(in: section)
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell: UITableViewCell!
        
        let hit = multiHitsViewModel.hitForRow(at: indexPath)
        
        if indexPath.section == 0 { // Query suggestion
            cell = tableView.dequeueReusableCell(withIdentifier: "querySuggestionCell", for: indexPath)
            cell.textLabel?.text = hit["query"] as? String
            cell.textLabel?.textColor = UIColor.gray
            cell.textLabel?.highlightedText = SearchResults.highlightResult(hit: hit, path: "query")?.value
            cell.textLabel?.highlightedTextColor = UIColor.black
            cell.textLabel?.isHighlightingInversed = true
        } else { // Instant Results
            cell = tableView.dequeueReusableCell(withIdentifier: "hitCell", for: indexPath)
            cell.textLabel?.text = hit["name"] as? String
            cell.textLabel?.highlightedText = SearchResults.highlightResult(hit: hit, path: "name")?.value
            cell.textLabel?.highlightedTextColor = UIColor.black
            cell.textLabel?.highlightedBackgroundColor = UIColor(red: 255 / 255, green: 255 / 255, blue: 100 / 255, alpha: 1)
            if let image = hit["image"] as? String, let imageUrl = URL(string: image) {
                cell.imageView?.contentMode = .scaleAspectFit
                cell.imageView?.setImageWith(imageUrl, placeholderImage: UIImage(named: "placeholder"))
            } else {
                cell.imageView?.image = UIImage(named: "placeholder")
            }
        }
        
        return cell
    }
    
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let hit = multiHitsViewModel.hitForRow(at: indexPath)
        
        if indexPath.section == 0 { // Query suggestion
            let query = hit["query"] as! String
            InstantSearch.shared.search(with: query)
        }
    }
    
    func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
        
        if section == 0 { // Query suggestion
            return nil
        }
        
        let label = UILabel(frame: CGRect(x: 12, y: 0, width: 300, height: 40))
        if tableView == self.tableView {
            if section == 1 {
                label.text = "Best results"
            }
        }
        
        let view = UIView()
        view.addSubview(label)
        view.backgroundColor = UIColor.lightGray
        return view
    }
    
    func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
        if section == 0 { // Query suggestion
            return 0
        } else {
            return 40
        }
    }
    
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 50
    }
    
    public func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
        searchViewModel.search(query: searchText)
    }
    
    public func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
        isTextBarClicked = true
        searchViewModel.search(query: searchBar.text)
    }
}

Did you find this page helpful?