UITextfield delegate method in mvvm - ios

I need to search the tableview in mvvm .
my viewmodel:-
function for search:-
func search(searchText :String?) {
filteredListArray = datasourceModel.dataListArray?.filter{($0.restaurantname?.range(of: searchText!, options: .caseInsensitive) != nil)}
}
And in the viewcontroller i just given the textfield delegate method.
my viewcontroller:-
class QM_SearchViewController: UIViewController,UITableViewDelegate,UITableViewDataSource, UISearchBarDelegate,UITextFieldDelegate {
#IBOutlet private weak var tableView: UITableView!
#IBOutlet weak var searchBar: UISearchBar!
#IBOutlet weak var txt: UITextField!
var isSearching = false
var search:String=""
var filteredSearchArray = NSMutableArray()
private var searchViewModel :QM_SearchViewModel!
init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?, withViewModel viewModel:QM_SearchViewModel) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
searchViewModel = viewModel
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
self.title = "SEARCH"
txt.delegate = self
searchViewModel.loadData { (isSuccess) in
if(isSuccess == true)
{
self.tableView.reloadData()
}
else{
}
}
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
print("While entering the characters this method gets called")
return true;
}
func textFieldShouldEndEditing(_ textField: UITextField) -> Bool { //delegate method
return false
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool { //delegate method
textField.resignFirstResponder()
return true
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return searchViewModel.numberOfRowsInSection(section: section)
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let identifier = "searchcell"
var cell: QM_SearchCell! = tableView.dequeueReusableCell(withIdentifier: identifier) as? QM_SearchCell
if cell == nil {
tableView.register(UINib(nibName: "QM_SearchCell", bundle: nil), forCellReuseIdentifier: identifier)
cell = tableView.dequeueReusableCell(withIdentifier: identifier) as? QM_SearchCell
}
cell.setsearchData(search: searchViewModel.datafordisplay(atindex: indexPath))
return cell
}
}
So in the textfield delegate HOW could i search.How could take the search function from viewmodel.How the searching tableview task take place

Just in side your shouldChangeCharactersIn you can call searchViewModel Search Method , if it not trigger update your dataSource Automatically , you will need to trigger your data source after call search Method
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if let text = textField.text,
let textRange = Range(range, in: text) {
let updatedText = text.replacingCharacters(in: textRange,
with: string)
if updatedText.count > 2 {
let result = searchViewModel.search(searchText :updatedText)
// result Should update your data Source searchViewModel.numberOfRowsInSection , and reload tableView
}
}
return true;
}

Related

Detecting textfieldshouldreturn from Custom TableViewCell in TableViewController to Add New Row

I want to add a new row in my TableView when the user presses the return key inside the Custom TableViewCell, which includes a TextField. However, I cannot find a way to do so... how do I view the events of the TextField in my TableView so I can add the row?
My TableViewController
class TableViewController: UITableViewController, CustomCellDelegate,
UITextFieldDelegate {
var rowCount = 1
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
}
// MARK: - Table view data source
...
// Doesn't Do Anything
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
let indexPath = IndexPath(row: rowCount-1, section: 1)
tableView.insertRows(at: [indexPath], with: .automatic)
view.endEditing(true)
return true
}
// Also does nothing
func didReturn(cell: AddActivityTableViewCell, string: String?) {
let indexPath = IndexPath(row: rowCount-1, section: 1)
tableView.insertRows(at: [indexPath], with: .automatic)
view.endEditing(true)
rowCount += 1
}
My CustomTableViewCell
protocol CustomCellDelegate: class {
func didReturn(cell: CustomTableViewCell, string: String?)
}
class CustomTableViewCell: UITableViewCell, UITextFieldDelegate {
#IBOutlet weak var textField: UITextField!
weak var delegate: CustomCellDelegate?
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
textField.delegate = self
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
public func configureTextField(text: String?, placeholder: String) {
textField.text = text
textField.placeholder = placeholder
textField.accessibilityValue = text
textField.accessibilityLabel = placeholder
}
public func editableTextField(editable: Bool) {
if editable == true {
textField.isEnabled = true
} else {
textField.isEnabled = false
}
}
// This works
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
delegate?.didReturn(cell: self, string: textField.text)
return true
}
}
Thanks!
I think you missed the set delegate in the cell . Please find the code below which works fine for me
ViewController
class TableViewController: UITableViewController, CustomCellDelegate, UITextFieldDelegate {
var rowCount = 1
override func viewDidLoad() {
super.viewDidLoad()
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return rowCount
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell : CustomTableViewCell = tableView.dequeueReusableCell(withIdentifier: "CustomCell", for: indexPath) as! CustomTableViewCell
cell.textField.placeholder = "Row \(indexPath.row)"
cell.delegate = self
return cell
}
func didReturn(cell: CustomTableViewCell, string: String?) {
rowCount += 1
let indexPath = IndexPath(row: rowCount-1, section:0)
tableView.beginUpdates()
tableView.insertRows(at: [indexPath], with: .automatic)
tableView.endUpdates()
view.endEditing(true)
}
}
Custom Cell
protocol CustomCellDelegate: class {
func didReturn(cell: CustomTableViewCell, string: String?)
}
class CustomTableViewCell: UITableViewCell, UITextFieldDelegate {
#IBOutlet weak var textField: UITextField!
weak var delegate: CustomCellDelegate?
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
textField.delegate = self
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
public func configureTextField(text: String?, placeholder: String) {
textField.text = text
textField.placeholder = placeholder
textField.accessibilityValue = text
textField.accessibilityLabel = placeholder
}
public func editableTextField(editable: Bool) {
if editable == true {
textField.isEnabled = true
} else {
textField.isEnabled = false
}
}
// This works
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
delegate?.didReturn(cell: self, string: textField.text)
return true
}
}

UISearchBar fetching data from Json

I am using api. I post some data and store response in tableview. I put searchbar for search data from tableview. I want when I write 3 words in searchbar after that my api will call and data show in the tableview. I am using uitextfield for searchbar.
var array = [String]()
var tabledata = [String]()
var tableFilterData = [String]()
var isSearch :Bool!
let cellReuseIdentifier = "cell"
#IBOutlet weak var searchTextfield: UITextField!
#IBOutlet weak var tableview: UITableView!
#IBOutlet weak var heightConstraint: NSLayoutConstraint!
#IBAction func textfieldchanged(_ sender: Any) {
tableview.isHidden = true
}
override func viewDidLoad() {
super.viewDidLoad()
isSearch = false
self.apicalling()
searchTextfield.addTarget(self, action: #selector(textFieldActive), for: UIControlEvents.touchDown)
}
public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool{
var searchText = textField.text! + string
if string == "" {
searchText = (searchText as String).substring(to: searchText.index(before: searchText.endIndex))
}
if searchText == "" {
isSearch = false
tableview.reloadData()
}
else{
getSearchArrayContains(searchText)
}
return true
}
func getSearchArrayContains(_ text : String) {
var predicate : NSPredicate = NSPredicate(format: "SELF CONTAINS[c] %#", text)
tableFilterData = (tabledata as NSArray).filtered(using: predicate) as! [String]
isSearch = true
tableview.reloadData()
}
override func viewDidLayoutSubviews()
{
heightConstraint.constant = tableview.contentSize.height
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?)
{
guard let touch:UITouch = touches.first else
{
return;
}
if touch.view != tableview
{
searchTextfield.endEditing(true)
tableview.isHidden = true
}
}
#objc func textFieldActive() {
tableview.isHidden = !tableview.isHidden
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
my tableview part is this
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if isSearch! {
return tableFilterData.count
}
else{
return tabledata.count
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell:UITableViewCell = tableView.dequeueReusableCell(withIdentifier: "cell") as UITableViewCell!
// Set text from the data model
if isSearch! {
cell.textLabel?.text = tableFilterData[indexPath.row]
cell.textLabel?.font = searchTextfield.font
}
else{
cell.textLabel?.text = tabledata[indexPath.row]
cell.textLabel?.font = searchTextfield.font
}
return cell
}
In my api calling my parameter is this
let param = ["var_name": "sha","API":"user_search","auth_token":authToken!]
but I want searchdata pass into the "var_name" .
my searchbar is working properly but I want when I write 3 words in searchbar after that api will call and that three data pass into the api as a parameters in "var_name".

Can we use Google's place autocomplete api to populate out tableview cells on swift?

I want to know the process of how we can use google place api so that when we enter a text in a UITextField, the tableview get reloaded to show the autocomplete results. The Documentation given on Google uses its own API. Im new to ios development. Can anyone help me how to proceed? So far i'm done with pod setup etc and i'm able to get text text enter by user in textfield's delegate method.
This is my code, im unable to see any result in my tableview
import UIKit
import GooglePlaces
class ViewController: UIViewController {
#IBOutlet weak var schoolTextField: UITextField!
#IBOutlet weak var schooltableView: UITableView!
var placesClient : GMSPlacesClient?
var resultArray = [String]()
override func viewDidLoad() {
super.viewDidLoad()
}
func placeAutocomplete(text:String) {
let filter = GMSAutocompleteFilter()
filter.type = .noFilter
placesClient?.autocompleteQuery(text, bounds: nil, filter: filter, callback: {(results, error) -> Void in //unable to enter in this block
if let error = error {
print("Autocomplete error \(error)")
return
}
if let results = results {
self.resultArray = [String]()
for result in results {
self.resultArray.append(String(describing: result.attributedFullText))
print("Result \(result.attributedFullText) with placeID \(result.placeID)")
}
}
self.schooltableView.reloadData()
})
}
}
extension ViewController:UITextFieldDelegate {
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let currentText = textField.text ?? ""
placeAutocomplete(text:currentText)
return true
}
}
extension ViewController:UITableViewDelegate,UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return resultArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)as! SchoolCell
cell.schoolLabel.text = resultArray[indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
//do something, unable to reach here
}
}
You forgot to instantiate GMSPlacesClient and to call delegate to UITextField and UITableView in viewDidLoad.
override func viewDidLoad() {
super.viewDidLoad()
self.placesClient = GMSPlacesClient()
self.schoolTextField.delegate = self
self.schooltableView.delegate = self
self.schooltableView.dataSource = self
}

Advanced Auto Complete Swift

I have created a simple autocomplete textfield (in which the autocomplete options are displayed in a tableview) through the following code:
import UIKit
class SchoolViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UITextFieldDelegate {
#IBOutlet weak var schoolTextField: UITextField!
#IBOutlet weak var autoCompleteTableView: UITableView!
let schoolPossibilities = ["Redwood", "Fisher", "Bellermen", "Saratoga", "Los Gatos", "Cambell", "Mooreland", "Harker", "Challenger", "Saint Andrews", "Beckens", "Lynbrook", "Menlo", "Gunn", "Aragon", "Kipp"]
var autoCompleteSchools = [String]()
override func viewDidLoad() {
super.viewDidLoad()
autoCompleteTableView.delegate = self
schoolTextField.delegate = self
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "someCell", for: indexPath)
cell.textLabel?.text = autoCompleteSchools[indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return autoCompleteSchools.count
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if let text = schoolTextField.text{
let substring = (text as NSString).replacingCharacters(in: range, with: string)
searchAutoCompleteEntries(withSubstring: substring)
}
return true
}
func searchAutoCompleteEntries(withSubstring substring: String){
autoCompleteSchools.removeAll()
for key in schoolPossibilities{
let string = key as NSString
let range = string.range(of: substring)
if range.location == 0{
autoCompleteSchools.append(key)
}
}
autoCompleteTableView.reloadData()
}
}
The problem is that options only show up if what's being typed in the textfield is an EXACT match. How do I change this code so it can tolerate both uppercase and lowercase letters and slight variations?
Use NSCaseInsensitiveSearch as compare option in
outputString.rangeOfString(String, options: NSStringCompareOptions, range: <#T##Range<Index>?#>, locale: <#T##NSLocale?#>)

Swift 1/2 TextField tag display all names

I have a text field that, when you type a name, should show a suggested name that get I from an array with JSON, the problem is that it shows only one name. For example if I type Tom it shows only Tom Cruise and not Tommy Gien. How can I resolve that?
CODE:
class ViewController: UIViewController, UITextViewDelegate, UITextFieldDelegate,UITableViewDataSource, UITableViewDelegate {
let save = NSUserDefaults.standardUserDefaults()
#IBOutlet var amountPoints: UILabel!
#IBOutlet var reasonView: UITextView!
#IBOutlet var toField: UITextField!
#IBOutlet var pointsField: UITextField!
#IBOutlet var autocompleteTableView: UITableView!
var pastUrls: [String] = []
var autocompleteUrls = [String]()
override func viewDidLoad()
{
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
toField.delegate = self
reasonView.layer.cornerRadius = 1
reasonView.layer.borderWidth = 0.7
reasonView.layer.borderColor = UIColor.grayColor().CGColor
autocompleteTableView.delegate = self
autocompleteTableView.dataSource = self
autocompleteTableView.scrollEnabled = true
autocompleteTableView.hidden = true
getallUser()
var Names = save.arrayForKey("give.Name")
pastUrls = Names as! [String]
print(pastUrls)
}
override func didReceiveMemoryWarning()
{
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool
{
autocompleteTableView.hidden = false
let substring = (textField.text! as NSString).stringByReplacingCharactersInRange(range, withString: string)
searchAutocompleteEntriesWithSubstring(substring)
return true // not sure about this - could be false
}
func searchAutocompleteEntriesWithSubstring(substring: String)
{
autocompleteUrls.removeAll(keepCapacity: false)
for curString in pastUrls
{
let myString:NSString! = curString as NSString
let substringRange :NSRange! = myString.rangeOfString(substring)
if (substringRange.location == 0)
{
autocompleteUrls.append(curString)
}
}
autocompleteTableView.reloadData()
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return autocompleteUrls.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let autoCompleteRowIdentifier = "AutoCompleteRowIdentifier"
let cell : UITableViewCell = tableView.dequeueReusableCellWithIdentifier(autoCompleteRowIdentifier, forIndexPath: indexPath) as UITableViewCell
let index = indexPath.row as Int
cell.textLabel!.text = autocompleteUrls[index]
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let selectedCell : UITableViewCell = tableView.cellForRowAtIndexPath(indexPath)!
toField.text = selectedCell.textLabel!.text
autocompleteTableView.hidden = true
}
func textViewDidBeginEditing(textView: UITextView) {
reasonView.text = ""
}
func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool {
if text == "\n"
{
textView.resignFirstResponder()
return false
}
return true
}
#IBAction func giveButton(sender: UIButton) {
}
#IBAction func returnButton(sender: UIBarButtonItem) {
self.dismissViewControllerAnimated(true, completion: nil)
}
Try replacing your method in seachAutocompleteEntriesWithSubtring with the following
func searchAutocompleteEntriesWithSubstring(substring: String)
{
autocompleteUrls.removeAll(keepCapacity: false)
for curString in pastUrls
{
var myString:NSString! = curString as NSString
var substringRange :NSRange! = myString.rangeOfString(substring)
if (substringRange.location == 0)
{
autocompleteUrls.append(curString)
}
}
autocompleteTableView.reloadData()
}

Resources