screenMonkey MonkeyMan
screenMonkey MonkeyMan

Reputation: 423

Why can't I search both first and last names using searchBar?

I have implemented code for searchBar and it works if I either search the first or the last name of a person. For example, if I want to search Kate Bell, the search works if I write "Kate", and it works if I write "Bell". But if I write "Kate B" the search result disappear.

Here's my code:

func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
    if searchText.count == 0 {
        isFiltered = false
        tableViewOutlet.reloadData()
    }else {
        isFiltered = true

        searchInternalArray = contactsInternalArray.filter({ object -> Bool in
            guard let text = searchBar.text else {return false}
            return object.firstName.lowercased().contains(text.lowercased().trimmingCharacters(in: .whitespacesAndNewlines)) || object.lastName.lowercased().contains(text.lowercased().trimmingCharacters(in: .whitespacesAndNewlines))
        })

        searchArrayGroups = sectionsArrayGroups.filter({ object -> Bool in
            guard let text = searchBar.text else {return false}
            return object.firstName.lowercased().contains(text.lowercased().trimmingCharacters(in: .whitespacesAndNewlines)) || object.lastName.lowercased().contains(text.lowercased().trimmingCharacters(in: .whitespacesAndNewlines))
        })

        searchArraySAEs = sectionsArraySAEs.filter ({ object -> Bool in
            guard let text = searchBar.text else {return false}
            return object.firstName.lowercased().contains(text.lowercased().trimmingCharacters(in: .whitespacesAndNewlines)) || object.lastName.lowercased().contains(text.lowercased().trimmingCharacters(in: .whitespacesAndNewlines))
        })


    tableView.reloadData()
}

I fond this on SO How to search by both first name and last name

It's in objective-c and I have trouble implementing it into my own code. I tried something like this:

searchInternalArray = contactsInternalArray.filter({ object -> Bool in
    guard let text = searchBar.text?.range(of: object.firstName + object.lastName) else {return false}
    return object.firstName.lowercased().contains(text.lowercased().trimmingCharacters(in: .whitespacesAndNewlines)) || object.lastName.lowercased().contains(text.lowercased().trimmingCharacters(in: .whitespacesAndNewlines))
})

That's obviously not how it should be implemented though.

Edit Didn't think it was relevant, but perhaps it is: I'm filtering multiple arrays since I have data coming from three different sources to the tableView. The whole searchBar code looks like above. It's updated.

Upvotes: 0

Views: 699

Answers (3)

steveSarsawa
steveSarsawa

Reputation: 1679

I got idea from flanker's answer.
This works for me

func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
         
        self.searchBar.showsCancelButton = true
        
        if searchText != ""{
            self.isSearchActive = true
            
            if self.object.count != 0{
                
                
                filteredContacts = self. object.filter(){
                //("\(($0 as FetchedContact).firstName.lowercased()) \(($0 as FetchedContact).object.lowercased()) \(($0 as FetchedContact).telephone.lowercased())")
                let name = ("\(($0 as ContactModel).firstName.lowercased()) \(($0 as ContactModel).lastName.lowercased()) \(($0 as ContactModel).mobileNumber.lowercased())")
                    return name.contains(searchText.lowercased())
                }
                
                
            }
            self.tblContactList.reloadData()
        }
        
     }

  • Which search on the base of FirsName, LastName and MobileNumber for Contacts.

Upvotes: 0

flanker
flanker

Reputation: 4200

Unless I'm missing something, there's a far simpler solution to this:

let name = firstname.lowercased() + " " + lastname.lowercased()
return name.contains(text.lowercased())

This works for any part of forename, surname, or the a part of the two with a space between. You should probably still trim leading/trailing spaces, and if you wanted to get rid of issues with variable spaces between the first and last names you could search/replace them double spaces with a single space.

Upvotes: 2

Scriptable
Scriptable

Reputation: 19750

Why not just create the full name from the two parts and search based on that.

let searchResults = contactsInternalArray.filter { object in
    "\(object.firstName) \(object.lastName)".contains(searchText)
}

You can still lowercase them and trim if you want to.

Upvotes: 1

Related Questions