So I'm using Swift 5 and working with core data. I'm trying to add validation to the textfields through the UIAlertView.
To give clarification to what my code already does:
User presses a button which the iOS Photo Library Interface Pops up.
Once photo is selected a UIAlertViewpops up and asks me two enter texts in two textfields.
Once that is done, the data is submitted to the database and displays the image and the texts that I entered onto a TableViewCell
The issue?
When submitting a blank text field, there is no prompt to tell the user to enter texts. It will just display the image only in the UITableViewCell without any texts which is the obvious result when inputting no strings.
What do I want to achieve?
To add a validation message to the user when they enter no text and cancel the process of submitting to the database.
What I've already tried?
Please see below for code. Note: Submitting an image and texts to the database already works, my issue is with textfield validation
func createBrandItem (with image:UIImage){
let brandItem = Brand(context: managedObjectContext)
brandItem.image = NSData(data: image.jpegData(compressionQuality: 0.3)!) as Data
let inputAlert = UIAlertController(title: "New Brand", message: "Enter an item and a brand.", preferredStyle: .alert)
inputAlert.addTextField { (textfield:UITextField) in
textfield.placeholder = "Item"
}
inputAlert.addTextField { (textfield:UITextField) in
textfield.placeholder = "Brand"
}
inputAlert.addAction(UIAlertAction(title: "Save", style: .default, handler: { (action:UIAlertAction) in
let itemTextField = inputAlert.textFields?.first
let productTextField = inputAlert.textFields?.last
if (itemTextField?.text!.isEmpty)! || (productTextField?.text!.isEmpty)! {
let alertBlankInput = UIAlertController(title: "Blank Input", message: "Please don't leave the textfields empty.", preferredStyle: .alert)
let okAction = UIAlertAction(title: "OK", style: UIAlertAction.Style.cancel)
alertBlankInput.addAction(okAction)
self.present(alertBlankInput, animated: true, completion: nil)
}
if itemTextField?.text != "" && productTextField?.text != "" {
brandItem.item = itemTextField?.text
brandItem.brand = productTextField?.text
do{
try self.managedObjectContext.save()
self.loadData()
}
catch{
print("Could not save data \(error.localizedDescription)")
}
}
}))
inputAlert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
if self.presentedViewController == nil {
self.present(inputAlert, animated: true, completion: nil)
}
else {
self.dismiss(animated: false, completion: nil)
self.present(inputAlert, animated: true, completion: nil)
}
}
Breaking the code down
The snippet below is what I tried adding to the createBrandItem function. When I add this ifstatement when debugging the app, it uses this conditional statement but also completes the conditional statement where it adds to the database.
if (itemTextField?.text!.isEmpty)! || (productTextField?.text!.isEmpty)! {
let alertBlankInput = UIAlertController(title: "Blank Input", message: "Please don't leave the textfields empty.", preferredStyle: .alert)
let okAction = UIAlertAction(title: "OK", style: UIAlertAction.Style.cancel)
alertBlankInput.addAction(okAction)
self.present(alertBlankInput, animated: true, completion: nil)
}
The code below is the snippet which adds the data to the database.
let brandItem = Brand(context: managedObjectContext)
brandItem.image = NSData(data: image.jpegData(compressionQuality: 0.3)!) as Data
if itemTextField?.text != "" && productTextField?.text != "" {
brandItem.item = itemTextField?.text
brandItem.brand = productTextField?.text
do{
try self.managedObjectContext.save()
self.loadData()
}
catch{
print("Could not save data \(error.localizedDescription)")
}
}
Summary
How would I go if the textfields are empty and stops the process of submitting to the database?
I'd recommend creating your own child view controller which you present as a model dialogue, which would be more elegant and give you far greater control over the process flow. However if you want to continue with an alert controller, you could make it work by creating the OK action in a disabled state:
let okAction = UIAlertAction(title: "OK", style: UIAlertAction.Style.cancel)
okActions.isEnabled = false
inputAlert.addAction(okAction)
and then use textFields' delegates to validate the content of the text fields (you'd need to have a means to coordinate between the two textfields - you could use the alertController's textfields? array to cross-check, or use local variables as flags) and when you're happy with the content of both
inputAlert.actions.filter({$0.title == "OK" }).first?.isEnabled = true
Related
I have an app that allows users to save their profile. In order for them to be able to sign up, I want to check and see if they have agreed to the apps terms and conditions. The issue I am having is if the user doesn't agree to them, they will see an alertController telling them to agree. However, the app still continues to execute the remainder of the code.
func checkIfChecked() {
if self.checkbox.imageView.isHidden == true {
let alert = UIAlertController(title: "Hold up!",message:" You must agree to our Community Guidelines before you can sign up.", preferredStyle: UIAlertController.Style.alert)
let continueButton = UIAlertAction(title: "Got it!", style: .default, handler: {(_ action: UIAlertAction) -> Void in
})
continueButton.setValue(GREEN_Theme, forKey: "titleTextColor")
alert.addAction(continueButton)
self.present(alert, animated: true, completion: nil)
}
if self.checkbox2.imageView.isHidden == true {
let alert = UIAlertController(title: "Hold up!",message:" You must agree to our Terms & Conditions before you can sign up.", preferredStyle: UIAlertController.Style.alert)
let continueButton = UIAlertAction(title: "Got it!", style: .default, handler: {(_ action: UIAlertAction) -> Void in
})
continueButton.setValue(GREEN_Theme, forKey: "titleTextColor")
alert.addAction(continueButton)
self.present(alert, animated: true, completion: nil)
}
}
#objc func handleRegister() {
checkIfChecked()
let hud = JGProgressHUD(style: .dark)
hud.textLabel.text = "Registering!"
hud.show(in: view)
guard let email = emailTextField.text, let password = passwordTextField.text, let name = nameTextField.text, let phonenumber = phonenumberTextField.text else {
print("Error")
return
the remainder of code....
}
}
if the checkBoxs are checked, there is no issue. But if they are not checked, then the users information will still be saved to the data base without them logging in. So I am trying to stop the execution of handleRegister after checkIfChecked is called only if the boxs were not checked.
Not sure if this is the safest way to fix the issue I am having, but what I did to fix the problem is inside of of the handleRegister, I added
checkIfChecked()
this has to be after the checkIfChecked that way the alertControllers can show.
if self.checkbox.imageView.isHidden == true {
return
} else if self.checkbox2.imageView.isHidden == true {
return
}
it does stop the execution of code if these lines are true.
I have an alert in my app where I put a textfield. The user can use it to add some values in an array. However I want all the values to be different. So if a user inserts an existing value, I want the textfield to be cleared and present a different placeholder text telling the user to insert a new value.
This is what I'm doing now:
func appendWord(){
let alertController = UIAlertController(title:"insert a word", message: nil, preferredStyle: UIAlertController.Style.alert)
alertController.addTextField { (textField : UITextField) -> Void in
textField.placeholder = "insert here"
textField.delegate = self
}
let cancelAction = UIAlertAction(title: "cancel", style: UIAlertAction.Style.cancel) { (result : UIAlertAction) -> Void in
}
let okAction = UIAlertAction(title: "save", style: UIAlertAction.Style.default) { (result : UIAlertAction) -> Void in
let newName = alertController.textFields![0].text! as String
//Useless Stuff to Append items here [...]
//If the item already exists then i call the following function which is inside of an if statement...
self.errorInCreation()
}
alertController.addAction(cancelAction)
alertController.addAction(okAction)
self.present(alertController, animated: true, completion: nil)
}
func errorInCreation(){
let alertController = UIAlertController(title:"Insert a new word", message: nil, preferredStyle: UIAlertController.Style.alert)
alertController.addTextField { (textField : UITextField) -> Void in
textField.placeholder = "The word already exists. Insert a new one"
textField.attributedPlaceholder = NSAttributedString(string: "The word already exists. Insert a new one",attributes: [NSAttributedString.Key.foregroundColor: UIColor.red])
textField.delegate = self
}
let cancelAction = UIAlertAction(title: "cancel", style: UIAlertAction.Style.cancel) { (result : UIAlertAction) -> Void in
}
let okAction = UIAlertAction(title: "save", style: UIAlertAction.Style.default) { (result : UIAlertAction) -> Void in
let newName = alertController.textFields![0].text! as String
//Useless Stuff to Append items here [...]
//If the item already exists then i call the following function which is inside of an if statement...
self.errorInCreation()
}
alertController.addAction(cancelAction)
alertController.addAction(okAction)
self.present(alertController, animated: true, completion: nil)
}
This should present a new alertViewController until the user inserts a new word. However this doesn't happen. When I press the save button, the alert closes.
I tried to edit the current alert but it's not really possible.
How could I clear the inserted text, change the placeholder name and let the user insert a new word?
I found this person who has my same problem but the solution pointed out here didn't work.
Presenting new AlertViewController after dismissing the previous AlertViewController - Swift
The solution is actually quite simple: don't use UIAlertController. It's just a specialized presented view controller, and you don't get much control over how it looks or behaves; in particular, it dismisses when a button is tapped, which is not what you want. So just use a custom presented view controller where you have the kind of control you're after.
I have a screen with a collection view, and a plus sign bar button item. When the plus sign is pressed, an alert window pops up, where the user can add information to the list. Upon hitting OK, I am trying to refresh the collection view, but I'm doing something wrong.
The print statement "passed guard" is achieved, and I can get the information they entered. Just can't refresh the view to reflect this without leaving and coming back. Any guidance? I've run into this a few times actually, so I'm clearly missing something. Thanks very much in advance.
#objc func newButtonPressed() {
let alert = UIAlertController(title: "Add", message: "", preferredStyle: .alert)
alert.addTextField { (textField) in
textField.placeholder = "Name"
}
alert.addAction(UIAlertAction(title: "Ok", style: .default, handler: { (action) in
var name = ""
guard let textFields = alert.textFields else { return }
guard let navController = self.parent as? UINavigationController else { return }
guard let settingsVC = navController.topViewController as? SettingsVC else { return }
print("passed guard") // success
DispatchQueue.main.async {
settingsVC.collectionView.reloadData()
settingsVC.view.backgroundColor = .red
// For testing purposes, explicitly using main thread and setting to red
}
}))
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
present(alert, animated: true, completion: nil)
}
May be you need to alter the collection dataSource
guard let textFields = alert.textFields else { return }
settingsVC.arr.append(textFields.first!.text!) // arr is collection dataSource
settingsVC.collectionView.reloadData()
I'm trying to create an alert with two input fields which contain a master password for this app. It's my first app. I saw a function online and wanted to see if it still works but it doesn't seem to pop up with the alert when the function is called. Has this been changed in Swift 4?
func showInputDialog() {
//Creating UIAlertController and
//Setting title and message for the alert dialog
let alertController = UIAlertController(title: "Choose Master Password", message: "Enter your Master and confirm it!", preferredStyle: .alert)
//the confirm action taking the inputs
let confirmAction = UIAlertAction(title: "Enter", style: .default) { (_) in
//getting the input values from user
let master = alertController.textFields?[0].text
let confirm = alertController.textFields?[1].text
if master == confirm {
self.labelCorrect.isHidden = true
self.labelCorrect.text = master
}
}
//the cancel action doing nothing
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel) { (_) in }
//adding textfields to our dialog box
alertController.addTextField { (textField) in
textField.placeholder = "Enter Master"
}
alertController.addTextField { (textField) in
textField.placeholder = "Confirm Password"
}
//adding the action to dialogbox
alertController.addAction(confirmAction)
alertController.addAction(cancelAction)
//finally presenting the dialog box
self.present(alertController, animated: true, completion: nil)
}
//1. Create the alert controller.
let alert = UIAlertController(title: "Title", message: "Description", preferredStyle: .alert)
//2. Add the text field. You can configure it however you need.
alert.addTextField { (textField) in
textField.placeholder = "User"
}
alert.addTextField { (textFieldPass) in
textFieldPass.placeholder = "Password"
textFieldPass.isSecureTextEntry = true
}
// 3. Grab the value from the text field, and print it when the user clicks OK.
alert.addAction(UIAlertAction(title: "Cancelar", style: .default, handler: { [weak alert] (_) in
print("cerrar")
}))
alert.addAction(UIAlertAction(title: "Aceptar", style: .default, handler: { [weak alert] (_) in
let textField = alert?.textFields![0]
let textFieldPass = alert?.textFields![1]
print("Text field: \(textField!.text)")
print("Text field: \(textFieldPass!.text)")
self.Autentificacion(usuario: textField!.text!, clave: textFieldPass!.text!)
}))
// 4. Present the alert.
self.present(alert, animated: true, completion: nil)
Going off as a reference to your question and daniel fernando muñoz melendez answer, I have written some code below.
//Create the alert controller.
let alert = UIAlertController(title: "Login", message: "For User", preferredStyle: .alert)
//Add the text field. You can configure it however you need.
alert.addTextField { (userField) in
userField.placeholder = "User"
}
alert.addTextField { (passWordField) in
passWordField.placeholder = "Password"
passWordField.isSecureTextEntry = true
}
//the cancel action doing nothing
let cancelAction = UIAlertAction(title: "Cancel", style: .destructive)
//the confirm action taking the inputs
let acceptAction = UIAlertAction(title: "Enter", style: .default, handler: { [weak alert] (_) in
guard let userField = alert?.textFields?[0], let passWordField = alert?.textFields?[1] else {
print("Issue with Alert TextFields")
return
}
guard let userName = userField.text, let passWord = passWordField.text else {
print("Issue with TextFields Text")
return
}
print("Text field: \(userName)")
print("Text field: \(passWord)")
// Condition Logic
})
//adding the actions to alertController
alert.addAction(acceptAction)
alert.addAction(cancelAction)
// Presenting the alert
self.present(alert, animated: true, completion: nil)
The guard statement for the alert.textFields act as a check to make sure the text fields are in fact created and are not nil.
The guard statement for the userField.text is to make sure that the text in them can be cast to a String. It should be noted that even if the user does not enter anything into the text fields it will still run properly. Since you want them to enter in credentials, I would assume you don't want this to happen and recommend putting your condition logic there. Or have it like daniel fernando muñoz melendez did it and have it in a separate function.
Let me know if you need any clarification.
I am working on an application that saves user's created images to the photo library. I need to attach a user name to each saved image so that I can recall these later. As far as I understand (please correct me if I am wrong), if I am saving to the photo library, I can't change the actual file name, so a way around this is to change modify the metadata and write the user name to the description for instance. However, I am completely stuck on how to accomplish this in Swift and I have searched everywhere for an answer. The code I have to save each UIImage is as follows: I have the save option and the input for a user name presented in an alert view.
// Create the alert controller
let alertController = UIAlertController(title: "Finished?", message: "Is this your attempt?", preferredStyle: .Alert)
// Create the actions
let okAction = UIAlertAction(title: "Yes, save", style: UIAlertActionStyle.Default) {
UIAlertAction in
NSLog("OK Pressed")
if let image = self.mainImageView.image{
UIImageWriteToSavedPhotosAlbum(image,self,Selector("image:withPotentialError:contextInfo:"),nil)
}
}
let cancelAction = UIAlertAction(title: "No", style: UIAlertActionStyle.Cancel) {
UIAlertAction in
NSLog("Cancel Pressed")
self.mainImageView.image = nil
}
alertController.addTextFieldWithConfigurationHandler { (textField : UITextField!) -> Void in
textField.placeholder = "Enter User Name"
self.inputTextField = textField
}
// Add the actions
alertController.addAction(okAction)
alertController.addAction(cancelAction)
// Present the controller
self.presentViewController(alertController, animated: true, completion: nil)
And I have another function for the image, which is as follows:
func image(image: UIImage, withPotentialError error: NSErrorPointer, contextInfo: UnsafePointer<()>) {
NSLog("\(self.inputTextField.text)")
let alertController = UIAlertController(title: "Success!", message:"Your image was saved", preferredStyle: .Alert)
//Some additional code here, specific to another part of the app that has to occur after the image is saved
self.presentViewController(alertController, animated: true){}
}
This code works to save an image, however I am completely at a loss for how to add anything to the metadata of an image. If anyone has any suggestions or advice it would be greatly appreciated and please let me know if anything is unclear and I can edit or clarify in the comments.