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
}
}
}
Related
I have a UITableView with 2 sections.
Each section has different xib cells (with multiple textfields, radio buttons etc.).
The user can enter those values using the keyboard.
How can I get the value of each text field at submit button using model?
Here is my model class for cell for detail section:
class DataModel {
var name: String?
var gender: String?
init(name: String?, gender: String?)
{
self.name = name
self.gender = gender
}
}
How I use it in my tableview:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier:"DetailCell") as? DetailCell
if cell == nil{
let arrNib:Array = Bundle.main.loadNibNamed("DetailCell",owner: self, options: nil)!
cell = arrNib.first as? DetailCell
}
let model: DataModel
model = DataModel [indexPath.row]
//displaying values
cell?.name_lbl.text = model.name
cell?.gender_lbl.text = model.gender
return cell!
}
First, you name_lbl and gender_lbl shoule be UITextField, not the UILabel.
You have to add target for the name_lbl and gender_lbl:
cell?.name_lbl.text = model.name
cell?.name_lbl.tag = indexPath.section
cell?.name_lbl.addTarget(self, action: #selector(textFieldNameDidChange(_:)), for: UIControl.Event.editingChanged)
cell?.gender_lbl.text = model.gender
cell?.name_lbl.tag = indexPath.section
cell?.name_lbl.addTarget(self, action: #selector(textFieldGenderDidChange(_:)), for: UIControl.Event.editingChanged)
and you add methods textFieldNameDidChange and textFieldGenderDidChange as:
#objc func textFieldGenderDidChange(sender: UITextField) {
var model = DataModel[sender.tag]
model.gender = sender.text
}
You should do the same for the "name".
You can give tag to textfield and use UITextFieldDelegate for this like,
func textFieldDidEndEditing(_ textField: UITextField) {
if textField.tag == 0 {
model.name = textField.text ?? ""
}
}
on you button submit, you can access model value like
#IBAction func submitButtonTapped(_ sender: Any) {
self.view.endEditing(true)
let name = model.name
}
For this u need to set tag to textfield in cell for row. In shouldChageCharacter delegate method set text to data array with respective indexpath and create the object of uitableviewcell and set text to the respective label. for get data you can get data from array. In above answer may be if u scroll table then TableCell will mix with eachother.
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!
}
I'm looking to get a UIButton to add its title value to the currently selected UITextField that's contained within a UITableViewCell.
I have a row of buttons with common phrases that a user might use, such as "#CompanyName". I have set the common phrases as the title of the buttons. Just below the row of buttons I have a UITableView with cells each containing several static labels and a text field. I want to allow the user to press one of the buttons above the table view to add the button's title value to the text field that is currently being edited.
I have managed to do this as a test using a text field and buttons both being outside of the table view using:
#IBAction func buttonAction(_ sender: AnyObject) {
buttonTitle = sender.titleLabel!.text!
testOutlet.text = "\(testOutlet.text!) \(buttonTitle)"
Now my question is how would I make this "testOutlet.text" dynamic so it only knows the text field that's being edited. I've looked into textFieldDidBeginEditing but couldn't figure it out. I have also tried defining the indexPath.
You need to know which UITextField is currently being edited. To do this, you can use the following code:
class ViewController: UIViewController {
// code ...
#IBAction func buttonAction(_ sender: AnyObject) {
buttonTitle = sender.titleLabel!.text!
oActiveTextField?.text = "\(oActiveTextField?.text ?? "") \(buttonTitle)"
}
fileprivate var oActiveTextField: UITextField?
}
extension ViewController: UITableViewDataSource {
// code ...
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: yourIdentifier, for: indexPath) as! YourTableViewCell
cell.textField.delegate = self
// TODO: configure cell
return cell
}
}
extension ViewController: UITextFieldDelegate {
func textFieldDidBeginEditing(_ textField: UITextField) {
oActiveTextField = textField
}
func textFieldDidEndEditing(_ textField: UITextField) {
oActiveTextField = nil
}
}
In my project thus far, I have successfully implemented a tableview whose cells populate postings from FIR database.
I can't figure out what code to add so that when the message user button is pushed, the poster's userID specific to that cell is identified and extracted. If I could get that far, I can extract the rest of the other user's info so that I can set up a chat that includes the receiver of the message's userID, userFirstName, and profile pic.
I would guess that tagging the button is a first step, but I'm not sure how that gets me the userID specific to that posting.
I don't even have code to show because I'm clueless in how to do this....
Put the button in cell. Also make a custom class of cell and put the userId or user object in that cell. When you tap the button you can get the userId etc from that cell.
Or if you want to get that event from cell to viewcontroller you can pass delegate to view viewcontroller. Some thing like this
//cellforrowatindexpath
cell.delegate = self
cell.indexPath = indexPath
// Your cell class
protocol CellDelegate: class {
func didTapCell(index: IndexPath)
}
#IBAction func buttonAction(_ sender: AnyObject) {
self.delegate?.didTapCell(index: indexPath)
}
//tag the cell button
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("HealerProfileCell", forIndexPath: indexPath) as! yourTVCell
cell.detailsButton.tag = indexPath.row
cell.detailsButton.addTarget(self, action: #selector(HealersTableViewController.performHealerDetailsInfoSegue(_:)), forControlEvents: .TouchUpInside)
return cell
}
//make a function
func performHealerDetailsInfoSegue(sender: AnyObject?) {
performSegueWithIdentifier("your segue identifier", sender: sender)
}
//use prepare for segue method
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let object = yourArray[(sender!.tag)]
if segue.identifier == "your segue identifier" {
let dvc = segue.destinationViewController as! YourVC
dvc.object = object
}
}
Add a target to your button in the TableView cellForItemAtIndexPath Method.
cell.yourButton.addTarget(self, action: #selector(CellButtonClicked), for: .touchUpInside)
Then add this function that is called when the button is pushed...
func CellButtonClicked(sender: UIButton) {
print("Clicked")
guard let cellInAction = sender.superview as? YourCell else { return }
guard let din = yourTableView?.indexPath(for: cellInAction) else { return }
// retrieve the specific values in the cell from your array
let specificCellData = yourArray[(indexPath as NSIndexPath).row]
}
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!
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
}
}