I'm having problems getting a text fields value from a UIAlertController. I am getting the value, but It seems to be executing my code in the wrong order. In the function below, I expect the function call to return a string, but the value is not set at the time the function returns.
#IBAction func btnSaveSession(sender: AnyObject) {
//Prompt user to enter session name
var sessionName: String = ""
sessionName = promptUserToEnterSessionName("Save Session", message: "Please enter the name of your custom session below.");
print("session Name: " + sessionName)
//Save session to firebase.
//redirect to create session controller.
}
func promptUserToEnterSessionName(title: String, message: String) -> String{
var sessionName: String = ""
//1. Create the alert controller.
let alert = UIAlertController(title: title, message: message, preferredStyle: .Alert)
//2. Add the text field. You can configure it however you need.
alert.addTextFieldWithConfigurationHandler({ (textField) -> Void in
textField.text = "Enter session name."
})
//3. Grab the value from the text field, and print it when the user clicks OK.
alert.addAction(UIAlertAction(title: "OK", style: .Default, handler: { (action) -> Void in
let textField = alert.textFields![0] as UITextField
print("Text field: \(textField.text)")
sessionName = textField.text!
}))
// 4. Present the alert.
self.presentViewController(alert, animated: true, completion: nil)
return sessionName
}
If anyone is having problems understanding my question, please comment and I will do my best to explain.
your ok action handler(closure) will call when you click on ok button. so instead of assign value to local variable sessionName , make a sessionName variable in class.
class YourClass {
var sessionName: String?
...
#IBAction func btnSaveSession(sender: AnyObject) {
//Prompt user to enter session name
promptUserToEnterSessionName("Save Session", message: "Please enter the name of your custom session below.");
}
func promptUserToEnterSessionName(title: String, message: String) {
//1. Create the alert controller.
let alert = UIAlertController(title: title, message: message, preferredStyle: .Alert)
//2. Add the text field. You can configure it however you need.
alert.addTextFieldWithConfigurationHandler({ (textField) -> Void in
textField.text = "Enter session name."
})
//3. Grab the value from the text field, and print it when the user clicks OK.
alert.addAction(UIAlertAction(title: "OK", style: .Default, handler: { (action) -> Void in
let textField = alert.textFields![0] as UITextField
print("Text field: \(textField.text)")
self.sessionName = textField.text!
self.testDemo()
}))
// 4. Present the alert.
self.presentViewController(alert, animated: true, completion: nil)
}
fun TestDemo() {
print("session Name: " + self.sessionName)
//Save session to firebase.
//redirect to create session controller.
}
}
You can use a Callback to get the value, like this:
func AlertPrompt(vista:UIViewController, titulo:String , mensaje:String, aceptar:String, completion: #escaping (_ resultado: String)->()) {
let miAlerta = UIAlertController(title: titulo, message: mensaje, preferredStyle: UIAlertControllerStyle.alert)
miAlerta.addTextField(configurationHandler: {
(textField) -> Void in
})
let okBoton = UIAlertAction(title: aceptar, style: UIAlertActionStyle.default, handler: {
(action) -> Void in
let result = miAlerta.textFields![0] as UITextField
// You return the value here
completion(result.text! as String)
})
miAlerta.addAction(okBoton)
let cancelBoton = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.cancel, handler: nil)
miAlerta.addAction(cancelBoton)
vista.present(miAlerta, animated: true, completion: nil)
}
And call the function like this:
AlertPrompt(vista: self, titulo: "Title", mensaje: "some message", aceptar: "Acept"){(resultado)->() in
print(resultado)
}
That works perfect for me, hope this help
This code:
let textField = alert.textFields![0] as UITextField
print("Text field: \(textField.text)")
sessionName = textField.text!
will be called only at the moment the button corresponding to the defined action is clicked. So at the moment of creation the UIAlertController it's not called.
Read about blocks in Swift, it should be clearer then.
Related
I have an alertview with textfield, and would like to make call if a user enters something in the text field and confirm it. I am confused how to handle this workflow.
func btnTapped(cell: UICollectionViewCell) {
let indexPath = self.collectionView.indexPath(for: cell)
openAlert()
// I want to move the following part once user enters textfield in the alertview
fetchData(urlString: url, data: data[indexPath.row]) { [weak self] (response, error) in
if error == nil
{
DispatchQueue.main.async {
//do any ui update here!
self?.collectionView.reloadData()
}
}
}
}
func openAlert(){
let alertController = UIAlertController(title: "Alert", message: "", preferredStyle: .alert)
alertController.addTextField { (textField : UITextField!) -> Void in
textField.placeholder = "Enter reason"
}
let saveAction = UIAlertAction(title: "Confirm", style: .default, handler: { alert -> Void in
if let textField = alertController.textFields?[0] {
if textField.text!.count > 0 {
print("Text :: \(textField.text ?? "")")
}
}
})
let cancelAction = UIAlertAction(title: "Cancel", style: .default, handler: {
(action : UIAlertAction!) -> Void in })
alertController.addAction(cancelAction)
alertController.addAction(saveAction)
alertController.preferredAction = saveAction
self.present(alertController, animated: true, completion: nil)
}
You need to work with the text field delegates and use textFieldDidChange, then anytime the text is changed on the alert, call the API. Here is a quick example:
func textFieldDidChange(_ textField: UITextField) {
// Make API call here
}
Then in the completion block for the API call, set whatever data you would like depending on if the API confirmed or did not confirm.
i am working at my startscreen (viewDidAppear). At the beginning of the app, there should be an alert with some notice message. This works fine. After you click "ok" at the notice, the next alert should pop up with a text field. In this text field you have to type in a double value. I need this double value to set up a lot of things inside the app, so I need this value outside the function to calculate with it.
E.g. The notice message describes how the app works. You click OK. Now the next alert pop up with the text field. For example it asks your height. After you type in your height and click OK the height-value is the main part of different calculations.
The problem is now, that my app works with the nil-value before I typed in the double value (e.g. height)
These are the snippets from the code.
var iNeedTheDataHere:String?
///Alerts
//Start
let startController = UIAlertController(title: "Notice", message: "notice message ", preferredStyle: .alert)
let inputController = UIAlertController(title: "Set input", message: "Please set the input", preferredStyle: .alert)
//BeforeScreenLoad
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
// Start Alert
startController.addAction(UIAlertAction(title: "OK", style: .default, handler:{(action:UIAlertAction!) in
self.input()
}))
self.present(startController, animated: true)
}
func input() {
inputController.addTextField()
let submitAction = UIAlertAction(title: "Submit", style: .default) { [unowned ac] _ in
let answer = inputController.textFields![0].text
iNeedTheDataHere = answer
}
inputController.addAction(submitAction)
}
When I set Breakpoints, I see that the value of the inputController is set to nil, before I typed in anything. I guess my mistake has something to do with the handler
Sorry for my English
Hope somebody can help me
let alert = UIAlertController(title: "Alert!!!", message: "Please enter your message ", preferredStyle: .alert)
alert.addTextField(configurationHandler: self.configurationTextField)
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler:{ (UIAlertAction) in
self.number.text?=""
MBProgressHUD.hide(for: self.view, animated: true)
}))
alert.addAction(UIAlertAction(title: "Done", style: .default, handler:{ (UIAlertAction) in
}))
self.present(alert, animated: true, completion: {
})
I have made some changes in your code to achieve that:
class ViewController: UIViewController {
let startController = UIAlertController(title: "Notice", message: "notice message ", preferredStyle: .alert)
let inputController = UIAlertController(title: "Set input", message: "Please set the input", preferredStyle: .alert)
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func viewDidAppear(_ animated: Bool) {
startController.addAction(UIAlertAction(title: "OK", style: .default, handler:{(action:UIAlertAction!) in
self.input()
}))
self.present(startController, animated: true)
}
func input() {
//Present another alert with textField
let confirmAction = UIAlertAction(title: "Submit", style: .default) { (_) in
guard let textFields = self.inputController.textFields,
textFields.count > 0 else {
// Could not find textfield
return
}
//get your textField
let answerTF = textFields[0]
let answer = answerTF.text
//Get values entered by user
print(answer)
}
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel) { (_) in }
//add your textField here
inputController.addTextField { (textField) in
//Set a placeholde for textField
textField.placeholder = "Answer"
}
inputController.addAction(confirmAction)
inputController.addAction(cancelAction)
self.present(inputController, animated: true, completion: nil)
}
}
I have added comment to explain what I am doing.
And your result will be:
You can also check demo project here.
I'm having trouble understanding Firebase's documentation. In my Login ViewController, I have a button that allows users to reset password. So when user presses the button, it opens an alert controller where user would have to input their email to be sent a password reset/ recovery.
#IBAction func forgottenPassword(sender: AnyObject) {
var loginTextField: UITextField?
let alertController = UIAlertController(title: "Password Recovery", message: "Please enter your email address", preferredStyle: .Alert)
let ok = UIAlertAction(title: "OK", style: .Default, handler: { (action) -> Void in
if loginTextField?.text != "" {
DataService.dataService.BASE_REF.resetPasswordForUser(loginTextField?.text, withCompletionBlock: { (error) in
if (error == nil) {
self.showErrorAlert("Password reset", msg: "Check your inbox to reset your password")
} else {
print(error)
self.showErrorAlert("Unidentified email address", msg: "Please re-enter the email you registered with")
}
})
}
print("textfield is empty")
})
let cancel = UIAlertAction(title: "Cancel", style: .Cancel) { (action) -> Void in
}
alertController.addAction(ok)
alertController.addAction(cancel)
alertController.addTextFieldWithConfigurationHandler { (textField) -> Void in
// Enter the textfiled customization code here.
loginTextField = textField
loginTextField?.placeholder = "Enter your login ID"
}
presentViewController(alertController, animated: true, completion: nil)
}
func showErrorAlert(title: String, msg: String) {
let alert = UIAlertController(title: title, message: msg, preferredStyle: .Alert)
let action = UIAlertAction(title: "OK", style: .Default, handler: nil)
alert.addAction(action)
presentViewController(alert, animated: true, completion: nil)
}
Does the Firebase Backend server automatically generate the code to send the user a reset to their email?
Would i have to provide further code? Such as sendPasswordResetForEmail()? ... Or does the Firebase Backend service handles it from here? ...
Is that the function you are looking for ?
resetPasswordForUser(email:withCompletionBlock:)
Just call it on your Firebase instance.
Then go to your app dashboard to customize email that will be send to user upon password changes.
(Using Swift 2 and Xcode 7)
I have a UIAlertController that prompt the user the enter a name.
I'm having difficulties getting the value that the user enters, so any heads up would be great.
I have the following code;
func promptUserToEnterSessionName() -> String{
let sessionNameController = UIAlertController(title: "Save your yoga session", message: "Please enter session name", preferredStyle: .Alert)
let cancelAction = (UIAlertAction(title: "Cancel", style: UIAlertActionStyle.Cancel, handler: nil))
let saveAction = (UIAlertAction(title: "Save", style: UIAlertActionStyle.Default, handler: enteredSessionName))
sessionNameController.addTextFieldWithConfigurationHandler {
(textField) -> Void in
self.sessionName = textField
}
sessionNameController.addAction(cancelAction)
sessionNameController.addAction(saveAction)
self.presentViewController(sessionNameController, animated: true, completion: nil)
//savedSessionName = (sessionNameController.textFields![0] as UITextField).text!
//print(savedSessionName)
return ""
}
func enteredSessionName(alert: UIAlertAction!){
print("sessionName" + String(sessionName))
}
So another possible solution is to save the whole UITextField in your member variable.
var textField: UITextField?
sessionNameController.addTextFieldWithConfigurationHandler {
(textField) -> Void in
self.textField = textField
}
func enteredSessionName(alert: UIAlertAction!){
print("sessionName" + String(self.textField.text))
}
I am trying to present an Alertcontroller that prompts the user for a filename and then use the filename elsewhere in the program. I have been trying numerous variations of the following code:
import UIKit
class ViewController: UIViewController {
var shortName: String!
#IBAction func saveFile(sender: AnyObject) {
//request filename with alert
var alertController:UIAlertController?
alertController = UIAlertController(title: "Enter File",
message: "Enter file name below",
preferredStyle: .Alert)
alertController!.addTextFieldWithConfigurationHandler(
{(textField: UITextField!) in
textField.placeholder = ""
})
let action = UIAlertAction(title: "Submit",
style: UIAlertActionStyle.Default,
handler: {[weak self]
(paramAction:UIAlertAction!) in
if let textFields = alertController?.textFields{
let theTextFields = textFields as [UITextField]
let enteredText = theTextFields[0].text
self!.shortName = enteredText //trying to get text into shortName
print(self!.shortName) // prints
}
})
alertController?.addAction(action)
self.presentViewController(alertController!,
animated: true,
completion: nil)
//do some stuff with the input
print(shortName) //THIS RETURNS nil if uncommented. comment out to avoid crash
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
I have thoroughly researched this and can't find how to either:
get the string value of shortName out of the UIAlertAction closure and into the shortName (I know that the current "self!.shortName" is unavailable outside the closure - doesn't matter what name I use - can't get it out)
If you run the program "as-is", the print(shortName) line will cause a crash due to unwrapping of nil. How can I get the alert to "wait" for input?
Most of the posted "solutions" have the same problem - they don't actually get the text input out of the closure and into a variable that can be accessed by the rest of the program.
thanks
Of course you get crash, shortName is nil while Submit button isn't pressed. You can try something like this:
#IBAction func saveFile(sender: AnyObject) {
var alertController:UIAlertController?
alertController = UIAlertController(title: "Enter File",
message: "Enter file name below",
preferredStyle: .Alert)
alertController!.addTextFieldWithConfigurationHandler(
{(textField: UITextField!) in
textField.placeholder = ""
})
let action = UIAlertAction(title: "Submit",
style: UIAlertActionStyle.Default,
handler: {[weak self]
(paramAction:UIAlertAction!) in
if let textFields = alertController?.textFields{
let theTextFields = textFields as [UITextField]
let enteredText = theTextFields[0].text
self!.shortName = enteredText //trying to get text into shortName
print(self!.shortName) // prints
self?.handleText()
NSOperationQueue.mainQueue().addOperationWithBlock({
self?.handleTextInMainThread()
})
}
})
alertController?.addAction(action)
self.presentViewController(alertController!,
animated: true,
completion: nil)
}
func handleText() {
print(self.shortName)
}
func handleTextInMainThread() {
print(self.shortName)
}
You have use NSOperationQueue if you want to work with UI inside handleTextInMainThread after user's input.
I think it is timing. You tried to print shortName right after presenting the alert. At that time the value is not set yet.
You can either use semaphore to wait till it is set or do whatever you want to do in the action closure for "submit".