BSK-Team
BSK-Team

Reputation: 1810

Filter a table that contains list of objects - Swift

I have a list of professional accounts that each contains a list of professional items.

I want to sort this list of professional accounts by retrieving all the professional items that contain a specific text.

Code :

func filterContentForSearchText(searchText: String) {

    self.listProfessionalAccountsFiltered = self.listProfessionalAccounts

    for professionalAccount in self.listProfessionalAccountsFiltered {
        professionalAccount.listProfessionalItems = searchText.isEmpty ? professionalAccount.listProfessionalItems : professionalAccount.listProfessionalItems.filter{ $0.title.lowercased().contains(searchText.lowercased()) }
    }

    self.listProfessionalAccountsFiltered = searchText.isEmpty ? self.listProfessionalAccounts : self.listProfessionalAccounts.filter { $0.listProfessionalItems.count > 0 }

    self.tableView.reloadData()
}

The search works well but when I delete, I lose data :

enter image description here

Why ?

EDIT

All code :

class ChangeAccountViewController: UIViewController {

    @IBOutlet weak var tableView: UITableView!

    var topInset: CGFloat = 0.0
    var initialTouchPoint = CGPoint.zero
    var listProfessionalAccounts = [ProfessionalAccount]()
    var listProfessionalAccountsFiltered = [ProfessionalAccount]()

    override func viewDidLoad() {
        super.viewDidLoad()

        self.setupUI()

        self.setupData()
    }

    func setupUI() {
        if #available(iOS 11.0, *) {
            self.topInset = UIApplication.shared.keyWindow?.safeAreaInsets.top ?? 0
        }
        self.view.frame = CGRect(x: 0, y: self.topInset, width: self.view.frame.size.width, height: self.view.frame.size.height)
    }

    func setupData() {

        self.listProfessionalAccounts.append(DATA1)
        self.listProfessionalAccounts.append(DATA2)
        self.listProfessionalAccounts.append(DATA3)
        self.listProfessionalAccounts.append(DATA4)

        self.listProfessionalAccountsFiltered = self.listProfessionalAccounts
    }

    @IBAction func close(_ sender: UIButton) {
        dismiss(animated: true, completion: nil)
    }

    @IBAction func handleGesture(_ sender: UIPanGestureRecognizer) {

        let touchPoint = sender.location(in: self.view?.window)

        if sender.state == UIGestureRecognizer.State.began {
            initialTouchPoint = touchPoint
        } else if sender.state == UIGestureRecognizer.State.changed {
            if touchPoint.y - initialTouchPoint.y > 0 {
                self.view.frame = CGRect(x: 0, y: self.topInset + touchPoint.y - initialTouchPoint.y, width: self.view.frame.size.width, height: self.view.frame.size.height)
            }
        } else if sender.state == UIGestureRecognizer.State.ended || sender.state == UIGestureRecognizer.State.cancelled {
            if touchPoint.y - initialTouchPoint.y > (view.bounds.height/3) {
                self.dismiss(animated: true, completion: nil)
            } else {
                UIView.animate(withDuration: 0.3, animations: {
                    self.view.frame = CGRect(x: 0, y: self.topInset, width: self.view.frame.size.width, height: self.view.frame.size.height)
                })
            }
        }
    }
}

extension ChangeAccountViewController: UITableViewDelegate, UITableViewDataSource {
    func numberOfSections(in tableView: UITableView) -> Int {
        return self.listProfessionalAccountsFiltered.count
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.listProfessionalAccountsFiltered[section].listProfessionalItems.count
    }

    func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        return self.listProfessionalAccountsFiltered[section].title
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = UITableViewCell()

        cell.textLabel?.text = self.listProfessionalAccountsFiltered[indexPath.section].listProfessionalItems[indexPath.row].title

        return cell
    }
}

extension ChangeAccountViewController:  UISearchControllerDelegate, UISearchBarDelegate {
    func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
        self.filterContentForSearchText(searchText: searchText)
    }

    func filterContentForSearchText(searchText: String) {

        self.listProfessionalAccountsFiltered = self.listProfessionalAccounts

        for professionalAccount in self.listProfessionalAccountsFiltered {
            professionalAccount.listProfessionalItems = searchText.isEmpty ? professionalAccount.listProfessionalItems : professionalAccount.listProfessionalItems.filter{ $0.title.lowercased().contains(searchText.lowercased()) }
        }

        self.listProfessionalAccountsFiltered = searchText.isEmpty ? self.listProfessionalAccounts : self.listProfessionalAccountsFiltered.filter { $0.listProfessionalItems.count > 0 }

        self.tableView.reloadData()
    }
}

ANSWER :

func filterContentForSearchText(searchText: String) {
    self.listProfessionalAccountsFiltered = self.listProfessionalAccounts.compactMap { professionalAccount in
        let filteredProfessionalAccountItems = professionalAccount.listProfessionalItems.filter { $0.title.lowercased().contains(searchText.lowercased()) }
        return searchText.isEmpty ? professionalAccount : (filteredProfessionalAccountItems.isEmpty ? nil : ProfessionalAccount(id: professionalAccount.id, title: professionalAccount .title, listProfessionalItems: filteredProfessionalAccountItems))
    }
    self.tableView.reloadData()
}

Upvotes: 1

Views: 668

Answers (1)

Roman Podymov
Roman Podymov

Reputation: 4521

Looks like you modify listProfessionalAccounts even if you copy it. Add the following init function to ProfessionalAccount if you still don't have it:

init(id: ID, title: TITLE, listProfessionalItems: LIST) {
    self.id = id
    self.title = title
    self.listProfessionalItems = listProfessionalItems
}

Use the following code to update listProfessionalAccountsFiltered:

func filterContentForSearchText(searchText: String) {
    self.listProfessionalAccountsFiltered = self.listProfessionalAccounts.compactMap { professionalAccount in
        guard !searchText.isEmpty else {
            return professionalAccount
        }
        let filteredProfessionalAccountItems = professionalAccount.listProfessionalItems.filter { $0.title.lowercased().contains(searchText.lowercased()) }
        return filteredProfessionalAccountItems.isEmpty ? nil : ProfessionalAccount(id: professionalAccount.id, title: professionalAccount.title, listProfessionalItems: filteredProfessionalAccountItems)
    }
    self.tableView.reloadData()
}

Upvotes: 1

Related Questions