Textfields getting cleared in tableview [duplicate] - ios

This question already has answers here:
How to get the values of multiple textFields in UITableView with dynamic cells?
(2 answers)
Closed 3 years ago.
I am currently creating an application and atm I am at the login and sign up function. I decided to create a tableview where I've textfields so the user can sign up. But every time I enter something in the textfield and scrolls down, the textfields is getting cleared out, but why?
Also, how can I add this data to my database when I tap a button? Since I cannot reach it from there. Any input?
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "signUpCell", for: indexPath) as! SignUpTableViewCell
cell.txtfield.delegate = self
cell.textOfField.text = textNames[indexPath.section][indexPath.row]
cell.txtfield.text = textFields[indexPath.section][indexPath.row]
#IBAction func signUpButtonTapped(_ sender: Any)
{
let authentication = Auth.auth().currentUser?.uid
//I know how to add it to the database, but how can I retrieve the tableview data here?
}

Cells are dequeud you need to update the data source array , this inside cellForRowAt
cell.textField.addTarget(self, action: #selector(textFieldDidChange(_:)), for: .editingChanged)
cell.textField.indexPath = indexPath
And
#objc func textFieldDidChange(_ textField: CustomTexf) {
let index = textField.indexPath
textFields[index.section][index.row] = textField.text!
}
Create this class and assign it to the textfield
class CustomTexf : UITextField {
var indexPath:IndexPath!
}

Related

How to access textview value which is inside tableview cell in swift 5?

I have one viewcontroller, inside that I have one table view and 2 buttons save and cancel.
In tableview cell i have one textview. after adding some text in textview i want to show that text. I am not sure how to get that tableview text on save button click. (number of rows may be dynamic).
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableview.dequeueReusableCell(withIdentifier: "SummaryManualEditContentCell", for: indexPath) as? SummaryManualEditTableCell {
cell.txtAnswers.text = "enter text here"
return cell
}
return UITableViewCell()
}
#IBAction func btnSave(_ sender: Any) {
print("textviewText1 + textviewText2 + and so on ")
}
In Addition to this on button click i want to add all that text multiple textviews into one string.
is there any clean and best way to achieve this?
Thank you for helping!
You need to get the indexPath of the cell whose text you want to get
get the cell for that indexpath like
#IBAction func btnSave(_ sender: Any) {
let indexPath = IndexPath(row: 0, section: 0)
if let cell = tableView.cellForRow(at: indexPath) as? SummaryManualEditTableCell {
let text = cell.txtAnswers.text
}
}
And if you have multiple cells with textFields you can loop around to get all fields
#IBAction func btnSave(_ sender: Any) {
var allTextViewsText = ""
for i in 0...5{
let indexPath = IndexPath(row: i, section: 0)
if let cell = tableView.cellForRow(at: indexPath) as? SummaryManualEditTableCell {
allTextViewsText += cell.txtAnswers.text
}
}
print(allTextViewsText)
}
But keep it in mind that this approach only works in the case of visible cells otherwise for non visible cells you will get nil
I will suggest you to implement textView:shouldChange in each cell who has textView with a delegate to the tableView's viewController. When text is changed in the cell, delegate should propagate the change to the viewController which will save the value in a variable.
Then, when you press on the save button, you would simply take values from variables.

UITextfield validation in swift4 - Dynamic cells

I have a Form (tableview with questions and textfields).
It is not static as data may change depending upon the form user select.
So I store these questions and validation constraints in a dictionary.
How can I validate these fields before user press submit ?
Code is given below :
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let Cell:FormTableViewCell = self.tableView.dequeueReusableCell(withIdentifier: "cellformid") as! FormTableViewCell
let dict = questions?[indexPath.row]
Cell.form_question_label.text = dict?.question_name
Cell.form_answer_textfield.text = dict?.answer ?? ""
return Cell
}
//Submit Button Action
#IBAction func saveFormButtonPressed(_ sender: Any) {
//Here I do operations to save a Array which contain all attended answers.
}
NOTE : When I press submit button data entered by user is being saved to database, but Validation cannot be done,because if some question is unattended that is not stored in database and also is not attached to the Array. So I cannot check whether all Mandatory fields are completed.
Please suggest a method..
You can add to your UITextField:
textField.addTarget(self, action: #selector(textFieldDidChange(_:)), for: .editingChanged)
and then validate answers:
#objc func textFieldDidChange(_ textField: UITextField) {
//Validation
}
Try this.
for view in self.view.subviews {
if (view is UITextField) {
var textfield = view as! UITextField
if (textfield.text == "") {
// execute code
}
}
}

How to use UITableView for TextField input view

I currently have an app which uses UIPickerViews to allow users to select which answer they want for a text field (to avoid spelling mistakes etc).
However, I have found that the UIPickerView isn't really what I want to use because I haven't had great feedback from it when testing.
I have done some research into how to use a UITableView for text field inputs instead, so when the user clicks the Textfield, the user segues to a UITableView with the same options which would be provided by the UIPickerView. Once they click the cell with the option they are looking for it would segue back to the form with the result chosen inside the text field. I thought this would be a better user experience as I could also implement the search to help users narrow down the option they require quicker.
I have been trying to get this to work for a while now, but I'm quite new at coding and haven't been able to crack it yet. I would just like advice on how to approach this? I'm using Swift and the Storyboard to create my app.
Would I need to create a separate ViewController with a UITableView that loads the options and then move the value back to the form once the cell is clicked?
One approach would be to use a table view in separate view controller. lets call it choiceVC and pass data which text field was tapped.
Then send the data back to your form to show what user has selected.
Follow these steps
Detect user tap on text field and segue to choiceVC by implementing this delegate function of UITextField
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
//push your choiceVC and pass data
var textFeildTapped = ""
//note: chooseGameTextField should be text field's outlet
if textField == chooseGameTextField{
textFeildTapped = "games"
}else if textField == chooseActiviyTextField {
textFeildTapped = "activiy"
}
//first set identifier of your view controller by going to identity inspector and setting the value StoryBoard ID
if let controller = storyboard?.instantiateViewController(withIdentifier: "choiceVC") as? ProductDetailVc{
//pass which text field was tapped
controller.choicesToShow = textFeildTapped
navigationController?.pushViewController(controller, animated: true)
}
return true
}
Note: choiceVC should have a variable "choicesToShow" of type string
in viewdidload of choiceVC check the variable
if choicesToShow == "games" {
//populate your table view with games.
}else {
//check for other cases and proceed accordingly
//activiy, console etc
}
Implement didSelect delegate method of UITableView
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
//Pass data back to your form using **delegate pattern**. see link in notes below
}
Notes:
See screen shot of setting storyBoard ID
see how to implement table view if you dont know
https://stackoverflow.com/a/33234181/7698092
See how to pass data backward using delegate pattern
https://medium.com/#mayooresan/passing-data-between-viewcontrollers-via-delegate-protocols-4ecde4b167de
If you are looking for an alternative for picker view to select options you can use dropdown like controls Eg.
DropDown
RSSelectionMenu
I hope these libraries can solve your issues, best of luck
I hope this code work for you. it's wroking for me.
First view controller for textfiled form where you want to open tableview.for that use textfield Delegate.
First View Controller
func doSomething(text: UITextField, with data: String) {
text.text = data
}
func textFieldDidBeginEditing(_ textField: UITextField) {
let objGametableVC = self.storyboard?.instantiateViewController(withIdentifier: "GametableVC") as! GametableVC;
objGametableVC.delegate = self
objGametableVC.selectedTextField = textField
if textField == txtActivity{
objGametableVC.tblData.removeAll()
objGametableVC.tblData = ["act1","act2"]
}
else if textField == txtGameName{
objGametableVC.tblData.removeAll()
objGametableVC.tblData = ["gam1","game2"]
}
textField.resignFirstResponder()
self.navigationController?.pushViewController(objGametableVC, animated: true);
}
Second view Controller For tableview show and pass data from second to first controller
Second view Controller
var delegate: Delegate?
var tblData: [String] = [String]()
var selectedTextField:UITextField? = nil
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tblData.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let tblcell = tableView.dequeueReusableCell(withIdentifier: "gamelblCell", for: indexPath) as! gamelblCell
tblcell.lblName.text = tblData[indexPath.row]
return tblcell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let tblcell = tableView.cellForRow(at: indexPath) as! gamelblCell
let data = tblcell.lblName.text
delegate?.doSomething(text: selectedTextField!, with: data!)
self.navigationController?.popViewController(animated: true)
}

UITableViewCell tag changes after scrolling [duplicate]

This question already has answers here:
Swift: retrieving text from a UITextField in a custom UITableViewCell and putting it in an array
(2 answers)
Closed 5 years ago.
I am creating a form in UITableView. This form has a UILabel and UITextField in a prototype cell. Each UITextField has a unique tag.
When user clicks submit button, I want to get value from each UITextField using a tag.
Now the problem is I have 18 UITextField and when I enter values in the field and scroll the view to fill the remaining fields, after filling the data when I press submit button, the app crashes. It won't be able to find the tag of first UITextField.
I want to compare UITextFields value. But I don't want to collect all textfields value. I want to retrieve particular textfield value and compare it with other textfield value on the submit button click.
This is how my UITableView Looks
Here is my code:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "SurveyFormTableViewCell", for: indexPath) as! SurveyFormTableViewCell
var pest_code = textfield_id_value[indexPath.row].pest_code
var srno = textfield_id_value[indexPath.row].srno
var inspection_no = textfield_id_value[indexPath.row].inspection_no
cell.text_field.layer.cornerRadius = 3
cell.text_field.layer.borderWidth = 1
cell.text_field.addTarget(self, action: #selector(tableFieldDidChange(_textField:)), for: .editingChanged)
let id:Int = Int("\(srno)\(pest_code)\(inspection_no)")!
cell.text_field.tag = id
cell.label?.text = struc_array[indexPath.item].pest
cell.label?.numberOfLines = 0
cell.label?.lineBreakMode = NSLineBreakMode.byWordWrapping
cell.layer.borderWidth = 1
return cell
}
#IBAction func submit_survey_clicked(_ sender: UIButton) {
text_field = self.table_view.viewWithTag(textfield_tag1) as! UITextField
text_field2 = self.table_view.viewWithTag(textfield_tag2) as! UITextField
}
This isn't going to work for a couple of reasons:
1) The table view cells are reused. So you get the cell for the first item and assign it say tag 1 but then as you scroll that cell gets reused for say cell 15 (just an example) and you assign the tag the number 15. Now the SAME textfield that had the tag 1 has the tag 15.
2) You are looking on your table view for a view with the text field tag but the text field is not a sub view of the table view it belongs to the cell instead so it will never be found.
EDIT
This is a very basic example of using a data model Basic Data Model Example
(Note: this won't stay available for ever I may delete it in a week or so)
(Also Note: this is a very basic example and not in anyway the most complete method with proper validation, etc).
EDIT
If you want to make a list of the values that have been entered for each unique entry in your data list you can use a dictionary. This is an example based on the details you have supplied in the comments:
First change the textfieldId struct so that it adopts the Hashable protocol and can therefore be used as the key in your dictionary like this:
struct textfieldId: Hashable {
var srno:Int
var pest_code:Int
var inspection_no:Int
var hashValue: Int {
return srno.hashValue ^ pest_code.hashValue ^ inspection_no.hashValue
}
static func ==(lhs: textfieldId, rhs: textfieldId) -> Bool {
return lhs.srno == rhs.srno && lhs.pest_code == rhs.pest_code && lhs.inspection_no == rhs.inspection_no
}
}
Then define a dictionary to hold the details that have been entered for each of the data items like this:
var enteredValues: [textfieldId: String] = [:]
Now whenever the text entered changes you store it in the dictionary like this:
self.enteredValues[id] = textEntered // Update for your project
and to get the information back again (for example to update the cell) do this:
cell.textField.text = self.enteredValues[id] // Update for your project.
Doing this you have created a dictionary of the values that have been entered that is unique to each data item.
If you need to clear the list you can do this:
self.enteredValues.removeAll()
or create a new instance like this:
self.enteredValues = [:]
You must assign indexPath.row in cell forsizeitem. Like this
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "SurveyFormTableViewCell", for: indexPath) as! SurveyFormTableViewCell
var pest_code = textfield_id_value[indexPath.row].pest_code
var srno = textfield_id_value[indexPath.row].srno
var inspection_no = textfield_id_value[indexPath.row].inspection_no
cell.text_field.layer.cornerRadius = 3
cell.text_field.layer.borderWidth = 1
cell.text_field.addTarget(self, action: #selector(tableFieldDidChange(_textField:)), for: .editingChanged)
let id:Int = Int("\(srno)\(pest_code)\(inspection_no)")!
cell.text_field.tag = indexPath.row
cell.label?.text = struc_array[indexPath.item].pest
cell.label?.numberOfLines = 0
cell.label?.lineBreakMode = NSLineBreakMode.byWordWrapping
cell.layer.borderWidth = 1
return cell
}

Unable to assign the delegate to UITextField as it is in in Tableview [duplicate]

This question already has answers here:
Cannot assign a value of type ViewController to a value of type UITextFieldDelegate?
(4 answers)
Closed 6 years ago.
I have a table view. In that I am creating the UITextField dynamically.
But I am not able to fire the events in it.
func tableView(_ tableView: UITableView, cellForRowAt indexPath:IndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCell(withIdentifier: "cell",for: indexPath) as! DynamicTableCell
var dynamicTxtField1: UITextField = UITextField()
dynamicTxtField1.backgroundColor = UIColor.white
dynamicTxtField1.rightViewMode = .always
dynamicTxtField1.layer.cornerRadius = 5;
dynamicTxtField1.clipsToBounds = true
dynamicTxtField1.borderStyle = .roundedRect
// Here i am not able to assign the
//Error in this line // dynamicTxtField1.delegate = self
// Here object "self" is referring to the view. Because of this i am not able to fire any events of the UITextField
cell.addSubview(dynamicTxtField1)
}
Please suggest how to assign the delegate to the UITextField in this scenario so that I can fire an event to show a view to pick some values from it.
The error is:
"Cannot assign the value of ViewName(classname) to type UITextFieldDelegate"
on the line:
dynamicTxtField1.delegate = self
enter image description hereYou should create your textField in your cell's subclass then modify its attributes in your cellForRowAtIndexPath. Does your class implement UITextFieldDelegate?
EDIT: try this
textField.addTarget(self, action: #selector(ViewController.textfieldDidchange(_:)), forControlEvents: .ValueChanged)
cell.contentView.addSubview(textField)
and here is the method
func textfieldDidchange(textField: UITextField) {
//your code
}

Resources