ReactiveCocoa 4 - Need help on validate input upon button tap - ios

I'm new to ReactiveCocoa, and I'm trying to figure out the syntax for validating form input upon button tap. There are quite a number of sample code for validTextSignal, but most of them either hooked into Action-enableIf, or handle UI bindings directly.
The idea is simple, I have a login screen, with email and password input. What I want is to handle validation upon Login tap to show an UIAlertView (eg. "Please input your email").
Here's what I figured out after awhile, the code works, but I'm not certain whether this should be the way to do it.
self.s_formErrorMessage <~ combineLatest(s_email.producer, s_password.producer)
.map({ (email, password) in
if adminNumber.isEmpty {
return "Please input admin number"
} else if password.isEmpty {
return "Please input password"
}
return ""
})
And here's how I use it, just simply use the value in button TouchUpInside
btn_login.rac_signalForControlEvents(.TouchUpInside).subscribeNextAs { (button: UIButton) in
if !self.viewModel.s_formErrorMessage.value.isEmpty {
self.showAlert("", message: self.viewModel.s_formErrorMessage.value)
}
}
Also, is there anyway we can capture Interrupted event from Action-enableIf false?
Any suggestion for better approach would be much appreaciated.
Cheers

Action use with button for disabled while do request (for example login request). So in this case need disabled button if not valid input.
Or binding error text in prompt text field if not valid.
But if you want just show alert with text error about failed valid fields you cat try this code:
btn_login.rac_signalForControlEvents(.TouchUpInside)
.toSignalProducer().map { [unowned self] _ in
return self.viewModel.s_formErrorMessage.value
}.filter { !$0.isEmpty }
.startWithNext { [unowned self] text in
self.showAlert("", message: text)
}

Related

How can I wait for observables to complete which aren't guaranteed to emit in the first place?

I am trying to figure out how to wait for an observable to be done in order to let another one emit a value.
Basically, backend sends me a series of actions I have to perform as a response to a GET API call.
Let's say the actions are:
Action 1
Action 2
Action 3
Currently, what I am doing is the following for every single action possible:
APIResponse
.filter{$0.0}
.subscribe(onNext: { flag in
//handle code here
}).disposed(by: disposeBag)
So I have three different blocks that look like the one above in my code, one for Action 1, another for Action 2 and another for Action 3.
Today, I did a test and enabled all of my actions at once. I got 2 alerts/view controllers showing on top of each other since all of my observables are emitting at the same time. And I got a warning for the third action which said that the VC was already presenting the alert and it couldn't present the third one (normally so).
I'd like to handle each action on its own no matter what the backend sends me so I could receive one action or 3 at once.
So what I want is to have the VC/alert disappear and completely be done with the handling of an action for another's to start.
If all actions came back empty, I expect the UI to do nothing and keep showing the homescreen.
Can anyone suggest anything useful?
Based on the information given, this should work:
let sharedResponse = apiResponse
let result1 = sharedResponse
.filter { $0.shouldDoAction1 }
.flatMap { _ in action1() }
let result2 = sharedResponse
.filter { $0.shouldDoAction2 }
.flatMap { _ in action2() }
Observable.concat(result1, result2)
.withLatestFrom(sharedResponse)
.filter { $0.shouldDoAction3 }
.subscribe(onNext: { _ in
action3()
})
.disposed(by: disposeBag)
The above assumes that action1() and action2() are of type () -> Observable<Void> and that they emit a completed event when they are done performing their action. They will also complete when the response emits a completion event, even if they didn't emit any next events.
My CLE library provides wrappers that will turn view controller presentation into an action. For example:
let result1 = sharedResponse
.filter { $0.shouldDoAction1 }
.flatMap(presentScene(animated: true) { _ in
UIAlertController(title: "Action1", message: nil, preferredStyle: .alert)
.scene { $0.connectOK() }
})

parsing UItextfield for incorrect format of entry

I want to get users to enter:
xyz http://www.example.org
in a textfield. But if they enter "http://www.example.org", I want to alert them immediately so they can add the "xyz" part ahead of it.
Whats the best way in Swift (2.x) to do this ? Thanks in advance.
let text = textField.text
if text.hasPrefix("xyz") {
// you're good
} else {
// give alert
}

Position a button (of Twitter Digits) programmatically in Swift

a newbie question :)
I'm trying to use Twiiter Digits for authentication (by phone number) in my (first) iOS app.
It is easier for my to understand how to position a button programatically when it is a button that i create. but this 1 line of code confuses me.
to embed their action button i just need to add this part of code (see documentation):
override func viewDidLoad() {
let digitsButton = DGTAuthenticateButton(authenticationCompletion: { (session, error) in
// Inspect session/error objects
})
self.view.addSubview(digitsButton)
}
My problem is that the creation of this button is automatically and have a completion handler, so when\where exactly do i have the option to position (format) it?
Thanks.
You can always create your own custom button and use the methods of Digits to perform the same actions. For example :
func didTapButton(sender: AnyObject) {
let digits = Digits.sharedInstance()
digits.authenticateWithCompletion { (session, error) in
// Inspect session/error objects
}
}
Also if you want to continue to customize your Digits button and it's View Controllers , you can find more here here.
It might sound strange but it took me some time to realize i can\need to do it after the completion handler (inside the ViewDidLoad...).
Thanks for Letting me know i can use my own button with Digits.

UITextfield not removing the icon even after the textfield is cleared

I have a form with two textfields and I want to validate those as I type. For example: I have an email textfield and as soon as I start typing it tells me whether the email has been previously used or not. If it is already used it shows an 'X' icon in the textfield and if it's not it shows a 'check mark'. The validation works fine. The problem I am facing is when I try to clear the textfield by pressing the delete button(not holding down) it clears the textfield and shows no icon because it's empty. But if it try to clear the textfield by holding down the delete button, then the icon does not disappear. Here's the code:
EmailAvailable.get(["email": newString], handler: {(result: [BaseModel]?, error: NSError?) in
if let available = result as? [EmailAvailable] {
self.emailImageView.image = available[0].available ? UIImage(named: "success") : UIImage(named: "failed")
} else {
self.emailImageView.image = UIImage(named: "failed")
}
})
I am making an API call here to check whether the email is valid or not. NOTE: The validation works fine.
the above image shows the check mark even after the textfield is cleared and only happens when I hold down the delete button. Any help is appreciated, thanks!

Value of textfield before "Editing Changed" event is fired

I want to know if there is a way to know the value of textfield before the value is changed to the new value.
For example:
If the text field had a value "a" and the user entered "b", so the editing changed event is fired. When I try to fetch the value of the text field in the debugger it will display "ab". Is there a way that I can get "a" before "b" was written?
Here is a piece of code where I am trying to fetch the value:
#IBAction func commentEditingChanged(sender: AnyObject) {
if(!((sender as? UITextField)!.text!.isEmpty)){
counter++
}
else
{
counter--
}
}
In this case I want to know if the text was empty before the user entered text because I don't want the counter increments every time the user enters a character. I want to increment once the user entered any text.
And please don't propose to use delegate function textField:shouldChangeCharactersInRange:replacementString because my question is about this IBAction method.
If there is no way to do that using this IBAction Method, is there is any other IBAction method that can achieve what i want?

Resources