iosguy
iosguy

Reputation: 9

Search bar returning only first element from data array

currently I am trying to implement my search bar, but something is wrong and I can't figure it out what it is. Here is the code, and explanation.

//global variable for empty array, its type of Any cause I am getting data from network call
var filteredData: [Any]!
//these are my models, which I am using to display them on screen after mapping in network function
var bookedTrips: [BookedTripsForView]?

func viewDidLoad() {
        super.viewDidLoad()
        filteredData = bookedTrips
}

func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
        searchBar.becomeFirstResponder()
        filteredData = []
        if searchText == "" {
            filteredData = bookedTrips
        }else {
            for trip in (bookedTrips)! {
                if trip.tripName.lowercased().contains(searchText.lowercased()){
                    filteredData.append(trip)
                  //if I type, lets say Barcelona, in console its printed correct result, 
                  //but its displaying only first trip in my array, which is Berlin
                    print("filteredDataArray after appending print: \(String(describing: filteredData))")
                }
            }
        }
        self.tableView.reloadData()
    }

I hope that my explanation is ok, if something's not clear, I will refactor my question. Thanks in advance.

Here is picture of my screen and console

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            if let filter = filteredData {
                return filter.count
            } else if let data = bookedTrips {
                return data.count
            }
            return 0
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: Cells.tripInfo) as! TripsListDetailCell
    
    if let trips = bookedTrips?[indexPath.row] {
        cell.configure(trips: trips)
    }
    return cell
}

Upvotes: 0

Views: 597

Answers (4)

iosguy
iosguy

Reputation: 9

And now, since I changed my variables to this :

var filteredData = [BookedTripsForView]()
var bookedTrips = [BookedTripsForView]()

I have one more problem in sections, added comment inside

    func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
    let cell = tableView.dequeueReusableHeaderFooterView(withIdentifier: Cells.sectionTitle) as! TripsListHeaderCell
    
    if isSearching {
        cell.configure(trips: filteredData[section])
    }
    else {
        cell.configure(trips: bookedTrips[section])
    }
    return cell
}

How should I implement function viewForHeaderInSection? In response inside every trip I get status of trip (current, upcoming, previous). I would like to sort them by status. If I put this inside viewForHeaderInSection :

if isSearching { 
  cell.configure(trips: filteredData[section])
} else { 
  cell.configure(trips:bookedTrips[section])
} 
return cell

I get index out of range on bookedTrips[section] If i comment that line, it works until I make mistake in search bar, lets say instead of Barcelona I type Bars, it throws error on filteredData[section] index out of range

In my response, every trip have trip status property which has type string, can I even sort them by that property?

Upvotes: 0

Kishan Barmawala
Kishan Barmawala

Reputation: 183

Short and simple (One line filter)

var filteredData = [BookedTripsForView]()
var bookedTrips = [BookedTripsForView]()

override func viewDidLoad() {
    super.viewDidLoad()
    bookedTrips = fetchFromAPIorDB()
    filteredData = bookedTrips
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return self.filteredData.count
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: Cells.tripInfo) as! TripsListDetailCell
    cell.configure(trips: filteredData[indexPath.row])
    return cell
}

func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
    if searchText.isEmpty {
        filteredData = bookedTrips
    }
    else {
        filteredData = bookedTrips.filter({ $0.tripName.lowercased().contains(searchText.lowercased()) })
    }
    self.tableView.reloadData()
}


Upvotes: 1

hessam
hessam

Reputation: 432

create enum for page mood like this for readable code:

enum PageMood {
    
    case normal
    case search
}

and create variable

var pageMode: PageMood = .normal

set normal for first first if search and change pageMode to search like this:

func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
    searchBar.becomeFirstResponder()
    if searchText == "" {
        pageMode = .normal
    }else {
        pageMode = .search
        filteredData = bookedTrips?.filter({ item -> Bool in
            return (item.tripName?.lowercased().contains(searchText.lowercased()) ?? false)
        })
    }
    
    self.tableView.reloadData()
}

change define datasource like this:

var bookedTrips: [BookedTripsForView]?
var filteredData: [BookedTripsForView]?

and inside set numberOfItem:

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    if pageMode == .search {
        return filteredData.count ?? 0
    } else {
        return bookedTrips.count ?? 0
    }
}

if only one item find، Maybe your data has only one item similar to the search text.

Upvotes: 0

Rahul Dasgupta
Rahul Dasgupta

Reputation: 924

 var isSearching: Bool = false // As global variable
 var bookedTrips: [BookedTripsForView]? = []
 var filteredData: [BookedTripsForView]? = []

 
 func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
    searchBar.becomeFirstResponder()
    filteredData = []
    if searchText == "" {
        isSearching = false
    }else {
        isSearching = true
        filteredData = bookedTrips.filter { (trip) -> Bool in
            if trip.tripName.lowercased().contains(searchText.lowercased()){
                return true
            } 
            return false
    }

        
    }
    self.tableView.reloadData()
}

//Tableview delegate

  func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

        if isSearching {
            return self.filteredData.count
        }
        return bookedTrips.count

}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
   let cell = tableView.dequeueReusableCell(withIdentifier: Cells.tripInfo) as! TripsListDetailCell

  if isSearching {
      cell.configure(trips: filteredData[indexPath.row])
  }
  else {
     cell.configure(trips: bookedTrips[indexPath.row])

  }
  return cell

}

Upvotes: 0

Related Questions