0

I have a UICollectionView containing a matrix of text fields. Since the number of text fields per row can be high, I implemented my custom UICollectionViewLayout to allow scrolling in this screen. When the user submits the form, I want to validate the value entered in every text field, thus I need to loop all the cells.

The problem that I'm facing is that I was using collectionView.cellForItemAtIndexPath for this but then found out that it fails with invisible cells, as I saw on this this question.

I understand the approach in the answer to store the values of the data source (in arrays) and then to loop the data source instead, however I don't know how to do this. I tried using function editingDidEnd as an @IBAction associated to the text field but I don't know how to get the "coordinates" of that text field. My idea behind this is to store the value just entered by the user in a two-dimensions array that I'll use later on to loop and validate.

Many thanks for your help in advance!

Community
  • 1
  • 1
David Lara
  • 51
  • 2
  • 11
  • If you know how many cells you have then you can make an index path (`indexPath = NSIndexPath(forRow: i, inSection: 1)` where i is the variable you're using for looping) and then get the cell: `self.collectionview!.cellForItemAtIndexPath(indexPath) as! YourCustomCollectionViewCell` – The Beanstalk Oct 12 '15 at 22:52
  • Thanks for your comment but, as I stated, collectionView.cellForItemAtIndexPath does not work for invisible cells (I get nil for those). – David Lara Oct 13 '15 at 11:58

1 Answers1

0

You don't have to loop invisible cells. Keep using datasource approach. What you are looking for is the way to map textFields to the datasource.

There are many solutions, but the easy one is using Dictionary.

Here's the code for UITableViewDataSource but you can apply it to UICollectionViewDataSource

class MyCustomCell: UITableViewCell{
    @IBOutlet weak var textField: UITextField!
}

class ViewController: UIViewController{

    // datasource
    var textSections = [ [ "one" , "two" , "three"] , [ "1" , "2" , "3"] ]

    // textField to datasource mapping
    var textFieldMap: [UITextField:NSIndexPath] = [:]


    // MARK: - Action
    func textChanged(sender: UITextField){

        guard let indexPath = textFieldMap[sender] else { return }
        guard let textFieldText = sender.text else { return }
        textSections[indexPath.section][indexPath.row] = textFieldText
    }

    @IBAction func submitButtonTapped(){

        // validate texts here
        for textRow in textSections{
            for text in textRow{
                if text.characters.count <= 0{
                    return print("length must be > 0.")
                }
            }
        }

        performSegueWithIdentifier("goToNextPage", sender: self)
    }

}

extension ViewController: UITableViewDataSource{

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

        let cell = tableView.dequeueReusableCellWithIdentifier("identifer") as! MyCustomCell

        // set value corresponds to your datasource
        cell.textField.text = textSections[indexPath.section][indexPath.row]

        // set mapping
        textFieldMap[cell.textField] = indexPath

        // add action-target to textfield
        cell.textField.addTarget(self, action: "textChanged:", forControlEvents: .EditingChanged)

        return cell
    }

    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return textSections[section].count
    }

    func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return textSections.count
    }

}
nRewik
  • 8,958
  • 4
  • 23
  • 30