UITextField in UITableViewCell and validation in modal view - iphone

I am using the approach described in this stackoverflow posting to retrieve values from a textfield. My problem is that the tableview is presented modally and I have a save button that validates the input and stores it.
The problem is that the textFieldDidEndEditing method is not called when the user clicks an UIBarButtonItem (= the save button, which closes the modal view).
In this event (when the user wants to save the input) I would like to validate it. But the values are stored in properties in the textFieldDidEndEditing. Due to the fact that this method is not called, I cannot validate the input values correctly.
Does anyone have a hint or solution on this?
Thanks in advance!

You should assign unique tag numbers to your text fields, then keep track on which is currently active (i.e. use a int iVar to store the active text fields tag value) in the textFieldDidBeginEditing delegate and when the user clicks the save, you should get the last textfield by it's tag value and then it's text value so you can validate it.

Okay, here we go:
Thanks to #Lefteris and his idea with storing the current index. Due to the fact that I cannot store the index into the tag attribute I decided to store the active indexPath and additionally the active textField. (I know, a reference to the UITextField would have been enough but I needed it for other stuff)
First I have added these two properties:
#property (nonatomic, strong) NSIndexPath *activeIndexPath;
#property (nonatomic, strong) UITextField *activeTextField;
Then I implemented textFieldDidBeginEditing: and textFieldDidEndEditing: of UITextFieldDelegate.
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
NSIndexPath *indexPath = (NSIndexPath*)[self.tableView indexPathForCell:(UITableViewCell*)[[textField superview] superview]];
self.activeTextField = textField;
self.activeIndexPath = indexPath;
}
- (void)textFieldDidEndEditing:(UITextField *)textField
{
NSString *input = textField.text;
//assuming values from input textfield into corresponding properties
[self assumeInput:input withIndexPath:self.activeIndexPath];
self.activeTextField = nil;
self.activeTextField = nil;
}
In textFieldDidEndEditing: I am storing the values into my properties (such as self.firstName, self.lastName, and so on...) by using the method [self assumeInput:input withIndexPath:self.activeIndexPath];.
In my saveAction-Method I am storing the value from the currently active TextField.
- (IBAction)saveButtonClicked:(UIBarButtonItem *)sender
{
//assuming input from active field (didEndEditing _not_ called right now!)
[self assumeInput:self.activeTextField.text withIndexPath:self.activeIndexPath];
//test output
NSLog(#"firstName: %#", self.firstName);
NSLog(#"lastName: %#", self.lastName);
NSLog(#"email: %#", self.email);
...
}
... and that's it!
Hope it helps! Thanks to #Lefteris for his input.
Best,
Chris

Related

How can I dismiss the keyboard programmatically?

I need a way of determining the UITextField that is currently selected in a view. Is this possible without passing a reference or tag?
To be more specific I need to be able to tell which UITextField is selected so that I can hide the keyboard. The reason I need this is because I want to create a UIToolbar to add to all the UITextField's as an input accessory. On this UIToolbar I will add a 'Done' button, when pressed this should hide the keyboard for the currently selected UITextField.
I assume you mean you want to know which UITextField is the first responder (which is the text field that gets input from the keyboard).
There is no public API for this (though there is a private API). You can track which text field is the first responder manually using the textFieldDidBeginEditing: method of each text field's delegate, or you can use a little trickery to find the first responder at any time.
Here's the trick. The UIApplication object knows which object is the first responder, and can send a message to it. So you write a category like this on UIResponder:
UIResponder+firstResponderHack.h
#import <UIKit/UIKit.h>
#interface UIResponder (firstResponderHack)
+ (UIResponder *)firstResponderByHack;
#end
UIResponder+firstResponderHack.m
#import "UIResponder+firstResponderHack.h"
#interface FirstResponderFinder : NSObject
#property (strong, nonatomic) UIResponder *firstResponder;
#end
#implementation FirstResponderFinder
#synthesize firstResponder = _firstResponder;
#end
#implementation UIResponder (firstResponderHack)
- (void)putFirstResponderIntoFinder:(FirstResponderFinder *)finder {
if (self.isFirstResponder)
finder.firstResponder = self;
}
+ (UIResponder *)firstResponderByHack {
FirstResponderFinder *finder = [FirstResponderFinder new];
// Sending an action to nil sends it to the first responder.
[[UIApplication sharedApplication] sendAction:#selector(putFirstResponderIntoFinder:) to:nil from:finder forEvent:nil];
return finder.firstResponder;
}
#end
Then you can find the first responder, and check whether it's a UITextField, like this:
UIResponder *firstResponder = [UIResponder firstResponderByHack];
if (firstResponder && [firstResponder isKindOfClass:[UITextField class]]) {
UITextField *textField = (UITextField *)firstResponder;
// do something with textField
}
There is an easy way to dismiss the keyboard without having to track the currently active control, or iterating through all the available controls, or using a UITextFieldDelegate.
[self.view endEditing:YES]
From the docs:
endEditing:
Causes the view (or one of its embedded text fields) to
resign the first responder status.
- (BOOL)endEditing:(BOOL)force
Parameters
force
Specify YES to force the first responder to resign, regardless of whether it wants to do
so.
Return Value
YES if the view resigned the first responder status or NO if it did not.
Discussion
This method looks at the current view and its subview
hierarchy for the text field that is currently the first responder. If
it finds one, it asks that text field to resign as first responder. If
the force parameter is set to YES, the text field is never even asked;
it is forced to resign.
There is a delegate method:
- (void)textFieldDidBeginEditing:(UITextField *)textField
Apple Docs:
This method notifies the delegate that the specified text field just
became the first responder. You can use this method to update your
delegate’s state information. For example, you might use this method
to show overlay views that should be visible while editing.
There is also a property:
#property(nonatomic, readonly, getter=isEditing) BOOL editing
Apple Docs:
A Boolean value indicating whether the text field is currently in edit
mode. (read-only)
Just make an ivar for the UITextView in your header file:
UITextField *editingField;
#property (nonatomic, copy) UITextField *editingField;
Then,
- (void)textFieldDidBeginEditing:(UITextField *)textField;
{
editingField = textField;
// Whatever else you want to do
}
I'm thinking that you need to diff the textFields without reference.
So, the recommended why is using ObjectiveC runtime.
It's pretty straight forward.
Firstly:
#import <objc/runtime.h>
Then, define a char for its address:
static char UITextFieldViewIdentifier;
Then set the identifier with something like this:
objc_setValue(textField, &UITextFieldViewIdentifier, #"Identifier") //typing on a phone, not so sure about the expression
In the delegate method:
NSString *identifier = objc_getObject(textField, &UITextFieldViewIdentifier)
Just call this line where you want to dismiss the keyboard:
[self.view endEditing:YES];

UITextField - want to show last character entered in full textfield

I am creating an iphone app, and I am using a UITextField. In my textfield, if the user fills the textfield, I would still like the user to see what they are text. I am not using the keyboard to fill the textfield - the values are getting filled in from buttons on a calculator. It there a way to make the textfield show the most recently entered values as it normally would with the keyboard?
Thanks.
Here is the code that populates the textfield:
- (IBAction)number:(id)sender {
NSString *entry = [sender currentTitle];
NSLog(#"%#", entry);
if(justOpenedCalculator){
total.text = #"";
total.text = [total.text stringByAppendingString:entry];
addFirstValueToDiscount = YES;
}else{
total.text = [total.text stringByAppendingString:entry];
addFirstValueToDiscount = YES;
}
justOpenedCalculator = NO;
}
I don't see why you could not do it with the textField. Just go over the UITextFieldDelegate methods in the Apple Documentation, and implement it. Here is the LINK !. You need to implement that and instead of doing a justOpenedCalculator you could utilize the textFieldDidBeginEditing method, and other delegate methods for your functions.
Make sure that you do a yourTextField.inputView = yourCustomKeyboard.
Make a
#property (nonatomic, retain) IBOutlet UITextField ...
And just assign the value to your textfield.

iPhone UItextfield entry saving method

Just ran into UX problem to save UITextField input value.I've got 6 UItextfield entries which saves individual value in sqlite db.
Right now each field has separate save button.So six ones quite look messy and silly.
I just want to know if there is any method to save entry after editing ends.
To be more concise...
I want to save data in UITextField after user ends editing.Just needs 'Saving Logic' for problem
You probably want to use an object which implements UITextFieldDelegate protocol. It defines –textFieldShouldEndEditing: and –textFieldDidEndEditing: methods which are called just before and once text editing ends.
Your delegate should be declared like:
#interface ATextFieldDelegate : NSObject<UITextFieldDelegate>
{
}
#end
And implements the methods:
#implementation ATextFieldDelegate
- (BOOL) textFieldShouldBeginEditing:(UITextField *)textField
{
// Test if the textField.text is valid for storage
// Return YES if it is, NO if not
}
- (void) textFieldDidEndEditing:(UITextField *)textField
{
// Store textField.text into your SQLite database
}
#end
And you should set your UITextField's delegate:
UITextField *myTextField; // could be an IBOutlet
ATextFieldDelegate *myTextFieldDelegate; // must be initialized somewhere
myTextField.delegate = myTextFieldDelegate;

How to pass values from one page to other page and display values in the page's textlabel of cell in iPhone?

I have an application in which when I click on the table item a new page opens, which allows me to enter details in textfield and textview, and clicking on the submit button it should navigate to the previous page which is a tableview and populate the the textlabel of the cell of the table view with the value which are entered in the textfield and textview.
How is this possible? How could I populate the tableview cell with the values entered in the textfield and textview?
Everything depends on how the data are stored in your TableView. For example if you have a plist file you must re-write this file when you submit new value.
After that, on :
- (void)viewWillAppear:(BOOL)animated {}
You must reload plist file and invok[self.tableView reloadData];
However there is an other method. If you have just few values you can use NSUserDefault class Reference to store data in your app.
You Need to use following delegate function:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
objInf.nameLable =[NSString stringWithFormat:#"Hello %# Have a Good Day :)",[listData objectAtIndex:indexPath.row]];
NSLog(#"Next View Value =%#",[listData objectAtIndex:indexPath.row]);
NSLog(#"Next View Value =%#",objInf.nameLable);
[self presentModalViewController:objInf animated:YES];
}
As
objInf is second class's object and nameLable is NSString which you can set as text of label of your second class where u want to display the data..
By using property you can do this. string properties of textfield strings on input page then simply by making object of that page you can access these property.
remember you need singletone object if you make new object then it reintialise the properties.
so use this for making object of that input class.
YourClass *obj= (YourClass *)[self.navigationController.viewControllers objectAtIndex: [self.navigationController.viewControllers count]-2];
this gives object from navigation stack.
That can be achieved by 2 ways.
One is, You can have 2 NSString property in another ViewController. 1 Method to assign data in that. like
#property (nonatomic,retain) NSString *textfieldValue; and Synthesize it.
#property (nonatomic,retain) NSString *textviewValue; and Synthesize it.
-(void) contentToDisplay: (NSString *)pTxtFieldValue txtViewValue(NSString*)pTxtViewValue{
self.textfieldValue = pTxtFieldValue;
self.textviewValue = pTxtViewValue;
}
While switching to another ViewController by submitting use its object to assign text like
[objViewController contentToDisplay:#"textfieldvalue" txtViewValue:#"textviewValue"];
Hope it helps.

[(NSString) becomeFirstResponder];?

Hey does anyone know how to do something like:
[(NSString) becomeFirstResponder];
(where NSString goes thats where the textfields name is).
Any help appreciated.
Thanks
[(NSString) becomeFirstResponder]; will cause exception.
Use
[textField becomeFirstResponder]; to make your textfield as first responder.
where textField is the instance of your UITextField. Make sure that you have assigned IBoutlet for that.
If the corresponding view controller has instance variables or declared properties pointing to the text fields (e.g. IBOutlet), you could try:
UIViewController *containerViewController;
NSString *fieldName = #"someFieldName";
id field = [containerViewController valueForKey:fieldName];
if ([field isKindOfClass:[UITextField class]])
[(UITextField *)field becomeFirstResponder];
Bear in mind that Cocoa Touch has a tag mechanism that can be used to get a specific subview from an entire view hierarchy regardless of IB outlets, instance variables, or declared properties. Tags are integers that can be set via Interface Builder or programmatically, and usually there’s a constant for each integer representing a tag. For instance:
static const NSInteger kFirstNameTextFieldTag = 42;
UIView *containerView;
field = [containerView viewWithTag:kFirstNameTextFieldTag];
if ([field isKindOfClass:[UITextField class]])
[(UITextField *)field becomeFirstResponder];
You could extend this to feature a dictionary mapping field names (strings) to their corresponding tags, and then use the tag to get a particular field.