i am working on a searchbar.
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
filteredData = patientArray.filter({$0.lowercased().prefix(searchText.count) == searchText.lowercased()})
searching = true
tableView.reloadData()
}
In this above 2 images, If i am writting the exact same string, then i am getting the result . But if i am searching for any numbers like "20". then the result is empty.
How to fix the issue that if i search for any containing text(it may be numbers or text), i will get the result.
You are searching from the beginning of the string (prefix). If you want to search if a string contains a substring you have to use contains.
But there is a more efficient API, range(of:options:) which also avoids the repetitively calling of lowercased()
filteredData = patientArray.filter{$0.range(of: searchText, options: .caseInsensitive) != nil}
Related
I am wondering if there is a way to add characters automatically to a searchBar textField while the user is typing. For example, if the user typed 533 then I want to automatically add " X " to it. I tried to do the following:
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
if searchText.isEmpty == false {
if searchText.count > 2 {
searchText.insert(" X ", at: 3)
}
}
However, Xcode is displaying an error message next to searchText.insert(" X ", at: 3) stating:
Cannot use mutating member on immutable value: 'searchText' is a let constant
You can't modify the value of searchText. Method parameters are constants. Create a local variable with the new value. Then update the search bar's text.
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
if searchText.count > 2 {
var newText = searchText
newText.insert(" X ", at: 3)
searchBar.text = newText
}
}
But this still has issues that you need to work out. This doesn't account for the user moving the caret or the fact that you will add an X far too many times as the user enters more text into the search field.
I have a search bar that filters through an xml array of recipe titles. The problem is that I have to search the entire title, otherwise I don't see suggested results. For example, if I have "Whole Grain Waffles" and "Whole Wheat Bread" typing "Whole" returns nothing. Typing "Whole Grain Waffles" returns successfully. This is the searchBar function
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
if searchBar.text == nil || searchBar.text == "" {
isSearching = false
view.endEditing(true)
myTableView.reloadData()
} else {
isSearching = true
filteredData = tableViewDataSource.filter({$0.title == searchBar.text})
myTableView.reloadData()
}
}
I'm pretty sure the solution has to do with case sensitivity, and returning certain characters when setting the filteredData. Thanks for help in advance
You could use contains to filter any item in array that contains the text or you can also use hasPrefix, if you want to search for the strings that start with the search text.
Something like this,
filteredData = tableViewDataSource.filter { $0.title.contains(searchBar.text) ?? "" }
Or,
filteredData = tableViewDataSource.filter { $0.title.hasPrefix(searchBar.text) ?? "" }
Using range worked in my situation
filteredData = tableViewDataSource.filter({$0.title.range(of: searchBar.text!) != nil})
I'm implementing a tagging feature similar to that of Facebook. So when I type # and some character(s) after it, the function should return the word being typed.
So if the textView contains (and the cursor is at c)
Hello #Jac !
The function should return "#Jac"
If it contains (and the cursor is at a)
Hello #Ja !
Then the function should return "#Ja"
The final string of both examples would be,
Hello Jack !
I have attempted multiple solutions but none are working. One particular question was very similar to my question, but the solution has errors. Here is the link.
Update 1
Here is how I've set the delegate on the textView,
postView.textView.delegate = self
This is the code for detecting if the # character was tapped (display the friends list table, if it was)
if let text = self?.characterBeforeCursor() {
if (text == "#" && self?.friends.count != 0) {
self?.friendTableView.isHidden = false
} else {
var word // Need to get the word being typed
self?.displayedFriends = (self?.displayedFriends.filter { ($0["firstName"]?.hasPrefix(word))! })!
}
}
Update 2
The solution below did not solve the problem. It is returning all text in the textfield instead of just the word that is being typed.
There is a delegate function called shouldChangeCharactersInRange. From there you can get the current text after the user tapped the letter.
Make sure you use UITextFieldDelegate in your class declaration and set the textField's delegate to self.
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
//get the updated text from the text field like this:
let text = (textField.text as NSString?)?.replacingCharacters(in: range, with: string)
//note that we *need* to use the text as NSString, because the delegate method gives us an NSRange, rather than a Range which we can't use on String, but NSString, so we need to convert that first
return true //so the text is visually updated in the textfield
}
Edit
I just saw that you posted about UITextView. It's pretty much the same:
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
let text = (textView.text as NSString?)?.replacingCharacters(in: range, with: text)
return true
}
Edit 2
You need to also assign the text view's text to your variable in the code snippet you provided:
} else {
var word = postView.textView.text
self?.displayedFriends = (self?.displayedFriends.filter { ($0["firstName"]?.hasPrefix(word))! })!
}
I have a very large array of data that I use a searchbar to filter. However I would like to filter only exactly that which the user enters in the searchbar. I.e. if you type "b" you only get items starting with b. The list is more than 200,000 items so now even with many letters entered the results showing are often irrelevant. I have tried searching a lot but every guide I have found is a variation of what I have :
extension MapTableController : UISearchResultsUpdating {
func filterContentForSearchText(_ searchText: String) {
if(searchText == "") {
matchingItems = []
}
else {
matchingItems = arrayOfFixes.filter { fix in
return fix.lowercased().contains(searchText.lowercased())
}
tableView.reloadData()
}
}
func updateSearchResults(for searchController: UISearchController) {
let searchText = searchController.searchBar.text
filterContentForSearchText(searchText!)
self.tableView.reloadData()
}
}
I understand that using "contains" will have the above mentioned effect. But I can't figure out how to filter it in the desired way. For example I would like it so that if I enter "Ben" it will show results like "Bendi", "Benhu", "Benji" etc. Not so that it shows results like "Juben", "Ibeno" etc, you get the picture.
Thanks for any help!
You can use 'hasPrefix' instead of 'contains' for your filter:
return fix.lowercased().hasPrefix(searchText.lowercased())
I have a tableview as shown in the picture below:
I want the filtering to happen based on both the labels in each cell of the Tableview. The result must be in the form of 2 labels .ie:if user searches for N it must displa NewYork ,Ny and print in the first cell ,Los AngelesCA and Nishat in the second and so on.Filter must filter both the arrays.Can we filter 2 arrays like in the below code:
func updateSearchResultsForSearchController(searchController: UISearchController) {
if let searchText = searchController.searchBar.text {
filteredData = data.filter({(dataString: String) -> Bool in
return dataString.rangeOfString(searchText, options: .CaseInsensitiveSearch) != nil
})
tableView.reloadData()
}
}
Can we pass 2 arrays to the filter? Or what method should I use to do the same?