Swift: Retrieving Text from a Uitextfield in a Custom Uitableviewcell and Putting It in an Array

Swift: retrieving text from a UITextField in a custom UITableViewCell and putting it in an array

There is a problem with your approach if the number of rows in your table exceeds the number that can fit on screen. In that case, the cells that scroll off-screen will be re-used, and the contents of the nameInput textField will be lost. If you can be sure that this will never happen, use the following code (in the method that handles button taps) to compose your array:

        var arrayOfNames : [String] = [String]()
for var i = 0; i<self.arrayOfPeople.count; i++ {
let indexPath = NSIndexPath(forRow:i, inSection:0)
let cell : EditingCell? = self.tableView.cellForRowAtIndexPath(indexPath) as EditingCell?
if let item = cell?.nameInput.text {
arrayOfNames.append(item)
}
}
println("\(arrayOfNames)")

Alternatively....

However, if it is possible that cells will scroll off-screen, I suggest a different solution. Set the delegate for the nameInput text fields, and then use the delegate methods to grab the names as they are entered.

First, add variables to your view controller, to hold the array and the row number of the text field currently being edited.

    var arrayOfNames : [String] = [String]()
var rowBeingEdited : Int? = nil

Then, in your cellForRowAtIndexPath method, add:

    cell.nameInput.text = "" // just in case cells are re-used, this clears the old value
cell.nameInput.tag = indexPath.row
cell.nameInput.delegate = self

Then add two new functions, to catch when the text fields begin/end editing:

func textFieldDidEndEditing(textField: UITextField) {
let row = textField.tag
if row >= arrayOfNames.count {
for var addRow = arrayOfNames.count; addRow <= row; addRow++ {
arrayOfNames.append("") // this adds blank rows in case the user skips rows
}
}
arrayOfNames[row] = textField.text
rowBeingEdited = nil
}

func textFieldDidBeginEditing(textField: UITextField) {
rowBeingEdited = textField.tag
}

When the user taps the button, they might still be editing one of the names. To cater for this, add the following to the method that handles the button taps:

        if let row = rowBeingEdited {
let indexPath = NSIndexPath(forRow:row, inSection:0)
let cell : EditingTableViewCell? = self.tableView.cellForRowAtIndexPath(indexPath) as EditingTableViewCell?
cell?.nameTextField.resignFirstResponder()
}

This forces the textField to complete editing, and hence trigger the didEndEditing method, thereby saving the text to the array.

How can I take the text from UITextFields in UITableViewCells in a UITableView and put them into an array (Swift 3)?

I am going to make a lot of assumptions here since you did not provide some sample code.

Lets say that you are using a UIViewController that has a UITableView inside it

class CalculatorViewController
@IBOutlet var tableView: UITableView!
var values: [Double] = []

override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
tableView.delegate = self
}
}

Now you have a basic viewController but the compiler will say that CalculatorViewController does not conform to UITableViewDataSource and UITableViewDelegate. Let's fix that

extension CalculatorViewController: UITableViewDataSource {

func numberOfSections(in tableView: UITableView) -> Int {
// return your number of sections, let say it's one
return 1
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// Let's say you only have 3 cells at the moment
return 3
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "YourCustomInputFieldCell") as! YourCustomInputFieldCell
return cell
}

}

Let's fix the UITableViewDelegate error

extension CalculatorViewController: UITableViewDelegate {
// This one gets called each time a cell will be displayed (as it says)
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
if let cell = cell as? YourCustomInputTextField {

// I assume that you expose your cell's input field
// By setting a tag on the input field you can
// distinguish it from other inputs

cell.input.tag = indexPath.row
cell.input.delegate = self
}
}
}

Again the compiler will complain that CalculatorViewController does not conform to UITextFieldDelegate. Let's fix that too.

extension CalculatorViewController: UITextFieldDelegate {

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
// Here you can check the tag of the textField
// and update the values array accordingly

// You should probably convert the string that you get to
// the number format that you want
return true
}
}

Hope it helps.

How to get user input from UItextfield and add it to an array?

As far as I could suggest (without any code insight given) you could do the following:

  1. Use a callback in your cell, which gets called every time the textfield ends editing:

.

class MyTableViewCell: UITableViewCell {
var textHasChanged: ((String) -> Void)?
...
}
extension MyTableViewCell: UITextFieldDelegate {
// this gets called every time the user ends editing the text field
func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
let newValue = textField.text //here you have your value

// now save it to your data source
self.textHasChanged(newValue)
}
}

  1. In a initializer or in awakeFromNib() function (depends on your usage), set the .delegate property of the textfield to self

  2. Now, to have each cell display the value from the datasource and to apply the changed text to your tableView datasource, add the following lines to your UITableViewController:

.

class MyTableViewController: UITableViewController {
var textArray: [String] = ["abc", "def"]
...
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "myCell", for: indexPath)

cell.textField.text = textArray[indexPath.row]
cell.textHasChanged = { (newValue) in
self.textArray[indexPath.row] = newValue
}
return cell
}

Just comment if you have further questions

Read Data From Text Field in TableView Dynamic Cell in Swift

I would change couple of things,

1. Get rid of numberOfTextFields

2. Use var cards = [Cards]() to return the number of cells in tableView

3. Initialize cards with a single Cards instance and set its property to nil. So I would have Cards implementation as

struct Cards {
var frontLabel: String?
var backLabel: String?
}

4. Initialize cards array as

var cards = [Cards()]

5. Return number of rows from arrays count

    func numberOfSections(in tableView: UITableView) -> Int {
return cards.count
}

6. I would migrate text field delegate responsibilities to Cell instead of moving it to ViewController and I would have a delegate in AddFCCell to update the ViewController about text changes

@objc protocol AddFCCellDelegate {
func updateCard(with frontText: String?, backText: String?, for cell: AddFCCell)
}

class AddFCCell: UITableViewCell {
weak var delegate:AddFCCellDelegate?
//.... other codes of yours
}

extension AddFCCell: UITextFieldDelegate {
func textFieldDidEndEditing(_ textField: UITextField) {
self.delegate?.updateCard(with: self.textField1.text, backText: self.textField2.text, for: self)
}
}

7. Finally, implement/confirm to AddFCCellDelegate in viewController and reload TableView bu updating text

extension ViewController: AddFCCellDelegate {
func updateCard(with frontText: String?, backText: String?, for cell: AddFCCell) {
guard let indexPath = self.tableView.indexPath(for: cell) else {
return
}
self.cards[indexPath.row].frontLabel = frontText
self.cards[indexPath.row].backLabel = backText
self.tableView.reloadRows(at: [indexPath], with: .automatic)
}
}

8. Update CellForRowAtIndexPath

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

let cell = tableView.dequeueReusableCell(withIdentifier: "AddFCCell") as! AddFCCell
cell.selectionStyle = .none
cell.delegate = self
cell.textField1.text = cards[indexPath.row].frontLabel
cell.textField2.text = cards[indexPath.row].backLabel

cell.backgroundColor = .purple

return cell
}

You can obviously implement a efficient protocol and return/update only specific variable in Cards struct based on which textField was modified n all, but the code posted here is only to give you an idea and to get started with

EDIT 1:

Make sure you have set your TextFields delegate right

    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
contentView.addSubview(textField1)
textField1.delegate = self
contentView.addSubview(textField2)
textField2.delegate = self

configureTextBox1(textField: textField1)
configureTextBox2(textField: textField2)
}

Retrieve textfield.text which is inside custom cell

Method 1:

Make an array of key pairs as-

    var arrayOfKeyPairs = [[String:Any]]()

arrayOfKeyPairs.append(["header":"xx",
"value" : "",
“id”: "dsd",
"order" : 0])

We are just replacing the default values with user input values as-

func textFieldDidEndEditing(_ textField: UITextField) {
let center: CGPoint = textField.center
let rootViewPoint: CGPoint = textField.superview!.convert(center, to: tableView)
let indexPath: IndexPath = tableView.indexPathForRow(at: rootViewPoint)! as IndexPath
arrayOfKeyPairs[indexPath.row ]["value"] = textField.text//here you are appending(replacing) data to array
}

On click of submit button, cross check what you received as-

func tapsOnNext(){
self.view.endEditing(true)//for adding last text field value with dismiss keyboard
print(arrayOfKeyPairs)
}

Method 2:
We can get cell data by accessing the cell with particular indexpath as

func tapsOnNext(){
let indexpath = IndexPath(row: 0, section: 0)
let cell = tableView.cellForRow(at: indexPath) as! CustomTableViewCell
print(cell.myTextField.text)
}


Related Topics



Leave a reply



Submit