Home > OS >  How to preserve the original indexPath.row after applying filters to Table View?
How to preserve the original indexPath.row after applying filters to Table View?

Time:09-17

My app uses "filter" buttons in which the whereField query is refined based on which filter buttons are pressed. This is an example before filtering: enter image description here

But this is an example after filtering: enter image description here

The issue is that when I click into one of the Rows, it takes me to the next page that corresponds to the original indexPath.row in my database belonging to that Row. How can I preserve the original indexPath.row? E.g., Cell B to always be indexPath.row = 1, even after filtering.

This is my cellForRowAt of my first View Controller.

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        
        // Get a cell
        let cell = tableView.dequeueReusableCell(withIdentifier: "MealPlanCell", for: indexPath) as! MealPlanCell
        
        // Get the mealPlan that the tableView is asking about
        let mealPlanInTable = mealPlan[indexPath.row]
        
        // Customize the cell
        cell.displayMealPlan(mealPlanInTable)
        
        // Return the cell
        return cell
        
    }

And how I connect this View Controller's indexPath.row to the next View Controller after a cell is tapped:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        
        // Detect the indexPath the user selected
        let indexPath = tableView.indexPathForSelectedRow
        
        // Get the mealPlan the user selected
        let mealPlanSelected = mealPlan[indexPath!.row]
        
        // Get a reference to the NextiewController
        let NextVC = segue.destination as! NextViewController
        
        // Get a reference to the currentMealPlanIndex in the NextViewController
        NextVC.currentMealPlanIndex = indexPath!.row
        
    }

Any advice is much appreciated!

CodePudding user response:

You are getting values from wrong array. Also it's better to pass the obj instead of index.

You need to have 2 variables - one for all data & other for filtered data. Use filtered data var in tableview datasource & for passing to NextVC.

Considering your class name is MealPlan. Here is the source.

var allMealPlans: [MealPlan]
var filteredMealPlans: [MealPlan]

func onFilterButtonPressed() {
  filteredMealPlans = allMealPlans.filter({
      // return true/false here based on your filters
   })
  tableView.reloadData()
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    
    // Get a cell
    let cell = tableView.dequeueReusableCell(withIdentifier: "MealPlanCell", for: indexPath) as! MealPlanCell
    
    // Get the mealPlan that the tableView is asking about
    let mealPlanInTable = filteredMealPlans[indexPath.row]
    
    // Customize the cell
    cell.displayMealPlan(mealPlanInTable)
    
    // Return the cell
    return cell
}

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    
    // Detect the indexPath the user selected
    let indexPath = tableView.indexPathForSelectedRow
    
    // Get the mealPlan the user selected
    let mealPlanSelected = filteredMealPlans[indexPath!.row]
    
    // Get a reference to the NextiewController
    let NextVC = segue.destination as! NextViewController
    
    // Get a reference to the currentMealPlanIndex in the NextViewController
    NextVC.currentMealPlan = mealPlanSelected
}

Add a variable in your NextVC for currentMealPlan

class NextVC: UIViewController {
  var currentMealPlan: MealPlan?
}

CodePudding user response:

Thank you all for the comments/advice! Instead of connecting the data in the view controllers through the indexPath, I used a document ID that is consistent with the data flowing between my view controllers. This works with all of my filtering.

This is in my first ViewController:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        
        if let indexPath = tableView.indexPathForSelectedRow {
            
            let ingredientsVC = segue.destination as! IngredientsViewController
            let documentID = mealPlan[indexPath.row].docID
            ingredientsVC.currentMealPlanIndex = indexPath.row
            ingredientsVC.passedDocID = documentID!
        }
    }

And this is in my second ViewController:

// This variable references the unique Document ID
var passedDocID = ""

// This is how I use that document ID to get a reference to the appropriate data
let selectedMealPlanIndex = mealPlan.firstIndex(where: {$0.docID == passedDocID})
            let currentMealPlan = mealPlan[selectedMealPlanIndex!]
  • Related