How to make UIDatePicker update textfield and database in Swift 4 - ios

In my app I have a form that has a textField that pulls up a UIDatePicker when clicked. When I select a new date from the UIDatePicker the textField does not update.
When debugging it seems like when a new date is selected the action isn't registered and it just sends over the same date.
Below is my code (Which I am planning on refactoring/cleaning up after resolving this issue)
import UIKit
import RealmSwift
class ClientDetailsViewController: UIViewController, UITextFieldDelegate, UIPickerViewDelegate, UIPickerViewDataSource {
let realm = try! Realm()
//Create Picker Views
let dateAppointedPickerView = UIDatePicker()
#IBOutlet weak var clientDateAppointedText: UITextField!
var selectedClient : Client? {
//Everything in the did set function will happen as soon as this variable is set with a value
didSet {
loadClientDetails()
}
}
override func viewDidLoad() {
super.viewDidLoad()
//Assign Picker Views
setPickerViews()
//Assign Picker View Settings
setPickerViewSettings()
//Assign Picker View Delegates
setDelegates()
}
//MARK: - Date Format Method
func formatDateToString(_ date: Date) -> String {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MMMM dd, yyyy"
dateFormatter.locale = Locale.current
let formattedDate = dateFormatter.string(from: date)
return formattedDate
}
func formatStringToDate(_ dateString: String) -> Date {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MMMM dd, yyyy"
dateFormatter.locale = Locale.current
let formattedDate = dateFormatter.date(from: dateString)
return formattedDate!
}
func loadClientDetails() {
loadViewIfNeeded()
clientDateAppointedText.text = formatDateToString((selectedClient?.dateAppointed)!)
}
//Send textfield/picker data to database
func textFieldDidEndEditing(_ textField: UITextField) {
var clientData : String = ""
guard let currentClient = selectedClient else {fatalError()}
switch textField {
case clientDateAppointedText:
clientData = "clientDateAppointedText"
updateClientDetails(currentClient, clientData)
default:
print("Did not edit anything")
}
}
//MARK: - Data Manipulation Methods
func updateClientDetails(_ clientInfo: Client,_ clientString: String) {
let editClient : String = clientString
do {
try realm.write {
switch editClient {
case "clientDateAppointedText":
clientInfo.dateAppointed = formatStringToDate(clientDateAppointedText.text!)
default:
print("Unable to edit client information")
}
}
} catch {
print("Unable to save client details")
}
}
I expect the Date Picker to update the textview every time a new date is chosen and for the value to be passed to the database to be updated. The actual result is that the value passed is the same date over and over again.

Steps to do it:
First intialize pickerview
var datePickerView:UIDatePicker = UIDatePicker()
Create action of textfield through storyboard i.e "Editing Did Begin"
#IBAction func textEditing(_ sender: UITextField)
{
isPickUpSelected = true
datePickerView = UIDatePicker()
datePickerView.minimumDate = Date()
datePickerView.date = selectedPickupDate
datePickerView.datePickerMode = UIDatePickerMode.date
sender.inputView = datePickerView
datePickerView.addTarget(self, action:
#selector(TUGBestDealVC.datePickerValueChanged), for:
UIControlEvents.valueChanged)
self.addToolBar(picker: datePickerView, textField: sender)
}
Write addToolbar function to customize datepicker:
func addToolBar(picker: UIDatePicker, textField: UITextField)
{
toolBar.barStyle = .default
toolBar.isTranslucent = true
toolBar.tintColor = UIColor.darkGray
toolBar.sizeToFit()
let doneButton = UIBarButtonItem(title: TUGHelpers().getLocalisedString(strKey:
"DONE"),style: .plain, target: self,
action:#selector(TUGBestDealVC.doneClick(sender:)))
doneButton.tag = picker.tag
let spaceButton = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target:
nil,action: nil)
let cancelButton = UIBarButtonItem(title:"Cancel", style: .plain, target: self,
action:#selector(TUGBestDealVC.cancelClick(sender:)))
cancelButton.tag = picker.tag+4
toolBar.setItems([cancelButton, spaceButton, doneButton], animated: false)
toolBar.isUserInteractionEnabled = true
textField.inputAccessoryView = toolBar
}
Track action of datepicker change date:
func datePickerValueChanged(sender:UIDatePicker)
{
self.setPickupDate(date: sender.date)
}
Here is done action of datepickerview:
#objc func doneClick(sender: UIButton)
{
self.setPickupDate(date: datePickerView.date)
dateTxt.resignFirstResponder()
}
Here is cancel action of datepickerview:
#objc func cancelClick(sender: UIButton)
{
dateTxt.resignFirstResponder()
}
Here you will get the date of pickerview:
func setPickupDate(date: Date)
{
print(date)
}
The same code you can update in the database every time
Enjoy, Happy coding.

Related

How do I print the age based on the selected date picker on a text field?

When I select the date the app stops responding. I want to select the date and show it in a textfield without pressing a done button. So I want to see date in live.
How do I print the age based on the selected Date picker on a TextField?
import UIKit
import Firebase
class SignUpEmailSegue0: UIViewController {
#IBOutlet weak var dateBirthday: UITextField!
#IBAction func dateBirthdayEdit(_ sender: UITextField) {
let datePickerView = UIDatePicker()
datePickerView.datePickerMode = UIDatePickerMode.date
sender.inputView = datePickerView
datePickerView.addTarget(self, action: #selector(handleDatePicker), for: UIControlEvents.valueChanged)
}
#objc func handleDatePicker(sender: UIDatePicker) {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "dd/MMM/yyyy"
dateBirthday.text = dateFormatter.string(from: sender.date)
}
}
Try changing your code as follows - using #selector() and exposing your function to #objc
datePickerView.addTarget(self, action: #selector(handleDatePicker), for: UIControlEvents.valueChanged)
#objc func handleDatePicker(sender: UIDatePicker) {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "dd-MM-yyyy"
dateBirthday.text = dateFormatter.string(from: sender.date)
}
To answer your second question of how to get the age:
let gregorian = Calendar(identifier: .gregorian)
let ageComponents = gregorian.dateComponents([.year], from: sender.date, to: Date())
if let age = ageComponents.year {
print(age)
}

UITextField not triggering action event upon UIDatePicker action event

I have a datePicker that updates my textField. Once the textField data changes is supposed to perform actions(such as verifying data). The problem is that after the datePicker updates the textField, the textField does not perform any actions, regardless of what action event I am using on the textField, such as .ValueChanged.I cannot figure out what the problem is. I noticed though, that if I am to type something in the textField, the action event works.
Here's my code:
class CustomTextField: UITextField, UITextFieldDelegate {
var customDelegate : CustomTextFieldDelegate?
enum type {
case standard
case date
}
var textFieldType : type = .standard {
didSet{
switch self.textFieldType {
case .standard:
break
case .date:
let datePicker = UIDatePicker.MMMddyyyy
self.inputView = datePicker
datePicker.addTarget(self, action: #selector(refreshOnDatePicker(_:)), for: .valueChanged)
self.addTarget(self, action: #selector(checkFieldInput), for: .applicationReserved)
break
}
}
}
#objc private func checkFieldInput(sender: CustomTextField){
guard let fieldInput = self.text else { return }
switch sender.textFieldType {
case .standard:
break
case .date:
customDelegate?.isTextFieldVerified = !fieldInput.isEmpty
break
}
}
#objc private func refreshOnDatePicker(_ selector: UIDatePicker){
self.text = selector.date.formattedMMMMddyyyy
}
}
fileprivate extension UIDatePicker {
class var MMMddyyyy : UIDatePicker {
let currentDate: NSDate = NSDate()
let calendar: NSCalendar = NSCalendar(calendarIdentifier: NSCalendar.Identifier.gregorian)!
calendar.timeZone = NSTimeZone(name: "UTC")! as TimeZone
let components: NSDateComponents = NSDateComponents()
components.calendar = calendar as Calendar
components.year = -100
let minDate: NSDate = calendar.date(byAdding: components as DateComponents, to: currentDate as Date, options: NSCalendar.Options(rawValue: 0))! as NSDate
let dp = UIDatePicker()
dp.datePickerMode = .date
dp.minimumDate = minDate as Date
dp.maximumDate = currentDate as Date
dp.backgroundColor = UIColor.white
return dp
}
}
fileprivate extension Date {
/// date formatted type "MMMM dd, yyyy"
var formattedMMMMddyyyy: String {
let formatter = DateFormatter()
formatter.dateFormat = "MMMM dd, yyyy"
return formatter.string(from: self)
}
}
Try this
#objc private func refreshOnDatePicker(_ selector: UIDatePicker){
self.text = selector.date.formattedMMMMddyyyy
self.checkFieldInput(sender:self)
}

How do I call the self.timer's changing value and indicate it at the label.text the ViewDidLoad's

I'm making a UILabel that indicates the value of the self.timer.
This is the code.
The problem is that I can't indicate the timeFormatter.stringFromDate(date_SSS) in the label.text.
Actually I also have a scrollView and a pageControl to scroll the label horizontally. But the main problem is at the UILabel and the self.timer.
import UIKit
class ViewController: UIViewController {
private var label: UILabel!
private var timer: NSTimer!
let intArray: String = ["12:00:00", "12:50:00", "15:30:00", "16:40:00"]
let i = 0
override func viewDidLoad() {
let timeFormatter = NSDateFormatter()
timeFormatter.dateFormat = "HH:mm:ss"
self.timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: "update:", userInfo: nil, repeats: true)
self.timer.fire()
for (var i = 0; i < intArray.count; i++) {
let label: UILabel = UILabel(frame: CGRectMake(CGFloat(index) * 50,100,150,200)
label.cornerRadius = 20
label.text = timeFormatter.stringFromDate(date_SSS)
view.addSubView(label)
}
}
func dateFromString(date:String) -> NSDate? {
let calendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)!
calendar.locale = NSLocale(localeIdentifier: "en_US_POSIX")
calendar.timeZone = NSTimeZone(abbreviation: "JST")!
let begin = date.startIndex
guard let hour = Int(date.substringWithRange(begin..<begin.advancedBy(2))),
let minute = Int(date.substringWithRange(begin.advancedBy(3)..<begin.advancedBy(5))),
let second = Int(date.substringWithRange(begin.advancedBy(6)..<begin.advancedBy(8))) else{
return nil
}
return calendar.dateBySettingHour(hour, minute: minute, second: second, ofDate: NSDate(), options: [])
}
func update(timer: NSTimer) {
let timeFormatter: NSDateFormatter = NSDateFormatter()
timeFormatter.timeZone = NSTimeZone(name: "GMT")
timeFormatter.dateFormat = "HH:mm:ss"
let time = dateFromString(intArray[i])
let remain = time!.timeIntervalSinceDate(NSDate())
let date_SSS = NSDate(timeIntervalSince1970: remain)
}
}
well, you are not setting your label in your update method, so it's hard to see how it would change. maybe I don't understand your question.

swift not updating textfield.text using UIDatePicker

In swift, I have a textField programmatically declared.
override func viewDidLoad() {
super.viewDidLoad()
textField3.delegate = self
textField3.returnKeyType = UIReturnKeyType.Next;
datePicker.datePickerMode = UIDatePickerMode.Date
datePicker.addTarget(self, action: Selector("handleDatePicker:"), forControlEvents: UIControlEvents.ValueChanged)
textField3.inputView = datePicker
}
func handleDatePicker(sender: UIDatePicker) {
textField3.text = dateFormatter.stringFromDate(sender.date)
}
All the other questions I've found similar to this deal with interface builder, and haven't helped. How would i fix this programmatically?
Xcode 9 • Swift 4
#objc func handleDatePicker(_ datePicker: UIDatePicker) {
textField3.text = datePicker.date.formatted
}
override func viewDidLoad() {
super.viewDidLoad()
datePicker.addTarget(self, action: #selector(handleDatePicker), forControlEvents: .valueChanged)
}
extension Date {
static let formatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "EEEE, dd MMM yyyy HH:mm:ss Z"
return formatter
}()
var formatted: String {
return Date.formatter.string(from: self)
}
}
Swift 3 version of #Leo Dabus answer:
func handleDatePicker(sender: UIDatePicker) {
textField3.text = datePicker.date.formatted
}
override func viewDidLoad() {
super.viewDidLoad()
datePicker.addTarget(self, action: #selector(handleDatePicker(sender:)), for: UIControlEvents.valueChanged)
}
extension Date {
var formatted: String {
let formatter = DateFormatter()
formatter.dateFormat = "EEEE, dd MMM yyyy HH:mm:ss Z"
return formatter.string(from: self as Date)
}
}
In, Swift 4
confirm to UITableViewDelegate
make txtFChequeDate.delegate = self
func textFieldDidBeginEditing(_ textField: UITextField) {
let datePickerView = UIDatePicker()
datePickerView.datePickerMode = .date
txtFChequeDate.inputView = datePickerView
datePickerView.addTarget(self, action: #selector(handleDatePicker(sender:)), for: .valueChanged)
if txtFChequeDate.text == "" {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "dd MMM yyyy"
txtFChequeDate.text = dateFormatter.string(from: Date())
}
}
#objc func handleDatePicker(sender: UIDatePicker) {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "dd MMM yyyy"
txtFChequeDate.text = dateFormatter.string(from: sender.date)
}

How do you make UIDatePicker a 24 hour system

I have a UIDatePicker that is set to the hour the minutes then AM/PM. How do I make it so that it is set to the 24 hour system like in the UK? For example 1 would be 13 and there wouldn't be AM or PM.
var datePicker = UIDatePicker()
datePicker.datePickerMode = UIDatePickerMode.Time
datePicker.locale = NSLocale(localeIdentifier: "en_GB") // using Great Britain for this example
Using Swift 4
I have used the following the method to help me achieve a time-picker without AM / PM.
Note i am using TextField as Inputview
func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
showTimePicker()
return true
}
func showTimePicker() {
timePicker.datePickerMode = .time
timePicker.locale = Locale(identifier: "en_GB") // Change to your locale
let toolbar = UIToolbar();
toolbar.sizeToFit()
let doneButton = UIBarButtonItem(title: "Done", style: .plain, target: self, action: #selector(doneTimePicker));
let spaceButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.flexibleSpace, target: nil, action: nil)
let cancelButton = UIBarButtonItem(title: "Cancel", style: .plain, target: self, action: #selector(cancelTimePicker));
toolbar.setItems([doneButton,spaceButton,cancelButton], animated: false)
modifiedHoursTextField.inputAccessoryView = toolbar
modifiedHoursTextField.inputView = timePicker
}
#objc func doneTimePicker() {
let timeFormatter = DateFormatter()
timeFormatter.dateFormat = "HH:mm"
modifiedHoursTextField.text = timeFormatter.string(from: timePicker.date)
self.view.endEditing(true)
}
#objc func cancelTimePicker() {
self.view.endEditing(true)
}
Bonus to JAL's answer, if you also want to be able to pick "date", you can use something like below:
viewDidLoad:
deadlineTF.inputView = deadlineDatePicker
deadlineDatePicker.timeZone = NSTimeZone.local
deadlineDatePicker.datePickerMode = UIDatePickerMode.dateAndTime
deadlineDatePicker.locale = Locale(identifier: "tr_TR")
deadlineDatePicker.backgroundColor = UIColor.white
deadlineDatePicker.layer.cornerRadius = 5.0
deadlineDatePicker.layer.shadowOpacity = 0.5
deadlineDatePicker.addTarget(self, action: #selector(onDidChangeDate), for: .valueChanged)
.
The Function:
// called when the date picker called.
#objc func onDidChangeDate(sender: UIDatePicker){
// date format
let myDateFormatter: DateFormatter = DateFormatter()
myDateFormatter.dateFormat = "dd/MM/yyyy HH:mm"
// get the date string applied date format
let mySelectedDate = myDateFormatter.string(from: sender.date)
deadlineTF.text = mySelectedDate
}

Resources