Search code examples
iosswiftuitableviewuiviewcontrolleruitextfield

how to Use a textfield as a "search bar" for a table view


I have a table view embedded into a regular view (as shown in this picture: Picture)

I have a search bar and working code so that when you start searching for a person's email, the table view automatically updates and just displays the people that match the search criteria.

Is there any way of using a textField in the first view as the search bar?

(if you look at the Picture, then the label that says "para" is where the user is going to type the email of their contact, can I use that label as the search bar, if so, how?)

in other words, how would I use "forField" as the search bar (forField is in the second bit of code)

here is the code for the tableView (currently working):

class UsersTableViewController: UITableViewController, UISearchResultsUpdating {
    
    func updateSearchResults(for searchController: UISearchController) {
        //update the search results
        filterContent(searchText: self.searchController.searchBar.text!)
    }
    

    @IBOutlet var usersTableView: UITableView!
    let searchController = UISearchController(searchResultsController: nil)
    
    var usersArray = [NSDictionary?]()
    var filteredUsers = [NSDictionary?]()
    
    var databaseRef: DatabaseReference!
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
 
        searchController.searchResultsUpdater = self
        searchController.dimsBackgroundDuringPresentation = false
        definesPresentationContext = true
        
        tableView.tableHeaderView = searchController.searchBar
        
        databaseRef = Database.database().reference()
        let usersRef = databaseRef.child("users")
        let query = usersRef.queryOrdered(byChild: "email")
        query.observe(.childAdded, with: {(snapshot) in
            self.usersArray.append((snapshot.value as? NSDictionary?)!)
            
            //insert the rows
            self.usersTableView.insertRows(at: [IndexPath(row:self.usersArray.count-1, section: 0)], with: UITableView.RowAnimation.automatic)
            
            
        }) { (error) in
            print(error.localizedDescription)
        }
        print("HOLAAAAAAAAAAA")
        print(self.usersArray)
        
        // Uncomment the following line to preserve selection between presentations
        // self.clearsSelectionOnViewWillAppear = false

        // Uncomment the following line to display an Edit button in the navigation bar for this view controller.
        // self.navigationItem.rightBarButtonItem = self.editButtonItem
    }

    // MARK: - Table view data source

    override func numberOfSections(in tableView: UITableView) -> Int {
        // #warning Incomplete implementation, return the number of sections
        return 1
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        // #warning Incomplete implementation, return the number of rows
        
        if ((searchController.isActive) && (searchController.searchBar.text != "")){
            return filteredUsers.count
        }
        return self.usersArray.count
    }

    
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)

        let user: NSDictionary
        if ((searchController.isActive) && (searchController.searchBar.text != "")){
            user = filteredUsers[indexPath.row]!
        }else{
            user = self.usersArray[indexPath.row]!
        }

        cell.textLabel?.text = user["email"] as? String
        cell.detailTextLabel?.text = user["name"] as? String
        
        return cell
    }
    
    func filterContent(searchText: String){
        self.filteredUsers =  self.usersArray.filter({ user in
            let userEmail = user!["email"] as? String
            return(userEmail?.lowercased().contains(searchText.lowercased()))!
        })
        
        tableView.reloadData()
    }
    

}

and for the view controller it is literally just the text fields and the labels.:

class PayViewController: UIViewController, STPAddCardViewControllerDelegate {       
    @IBOutlet weak var forField: UITextField!
    @IBOutlet weak var toField: UITextField!
    @IBOutlet weak var amountLabel: UILabel!

    override func viewDidLoad() {
        super.viewDidLoad()
    }
}

in other words, how would I use "forField" as the search bar

After recent comments and updates it, I added the following to payViewController:

override func viewDidLoad() {
    super.viewDidLoad()
    //var myTable:UsersTableViewController?
    myTable = self.children[0] as! UsersTableViewController
    self.toField.addTarget(self, action: #selector(UsersTableViewController.textChanges(_:)), for: UIControl.Event.editingChanged)
}

and changed the following functions in the table view controller:

func updateSearchResults(for searchController: UISearchController) {
        //update the search results
        filterContent(searchText: searchT)
    }

    
    @objc func textChanges(_ textField: UITextField) {
        let text = textField.text! // your desired text here
        // Now do whatever you want.
        searchT = text
    }

Solution

  • Your problem is accessing the child from the parent so you need to declare this inside PayViewController

    var myTable:UsersTableViewController?
    

    and inside viewDidLoad

    myTable = self.children[0] as! UsersTableViewController
    

    after that in chnage action of the textfeilds do

    myTable.filterContent(searchText:forField.text!)
    

    Btw you can also transfer the search bar related content inside the searchController or to remove that child segue and add a table directly below the fields and make everything inside PayViewController

    You don't have to use UITableViewController for utilizing table an instance of UITableView is sufficient and can be directly as a subview inside the vc