I've been searching far and long, and to this moment, I did not come across a working solution for PhoneGap / Cordova applications that would show soft keyboard programmatically.
Scenario:
We have a PhoneGap application - a website created in jQuery Mobile - that at one point shows a dialog to the user. This dialog is also a web page and has one single INPUT text box where user should enter a code.
Problem:
When the code dialog is shown, the input box is focused using JavaScript. However, due to restrictions placed on iPhone's internal browser, the soft keyboard does not come up until the user actually really clicks inside the input text box.
What we tried:
Any ideas?
EDIT: The restriction mentioned in this question is for built-in browsers only... if you're aiming Opera, you will be successful by using the following code:
var e = jQuery.Event("keydown", { keyCode: 37 });
$('#element').focus().trigger(e);
EDIT2: This is a final working PhoneGap code that can be used in a plugin:
keyboardhelper.h
//
// keyboardHelper.h
// soft keyboard displaying plugin for PhoneGap
//
// Copyright 2012 Martin Ambrus.
//
#import <Foundation/Foundation.h>
#ifdef CORDOVA_FRAMEWORK
#import <Cordova/CDVPlugin.h>
#else
#import "CDVPlugin.h"
#endif
@interface keyboardHelper : CDVPlugin {
NSString *callbackID;
}
@property (nonatomic, copy) NSString *callbackID;
- (void)showKeyboard:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options;
@end
keyboardhelper.m
//
// keyboardHelper.m
// soft keyboard displaying plugin for PhoneGap
//
// Copyright 2012 Martin Ambrus.
//
#import "keyboardHelper.h"
#import "AppDelegate.h"
@implementation keyboardHelper
@synthesize callbackID;
-(void)showKeyboard:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options {
self.callbackID = [arguments pop];
//Get text field coordinate from webview. - You should do this after the webview gets loaded
//myCustomDiv is a div in the html that contains the textField.
int textFieldContainerHeightOutput = [[((AppDelegate *)[[UIApplication sharedApplication] delegate]).viewController.webView stringByEvaluatingJavaScriptFromString:@"document.getElementById(\"myCustomDiv\").offsetHeight;"] intValue];
int textFieldContainerWidthOutput = [[((AppDelegate *)[[UIApplication sharedApplication] delegate]).viewController.webView stringByEvaluatingJavaScriptFromString:@"document.getElementById(\"myCustomDiv\").offsetWidth;"] intValue];
int textFieldContainerYOffset = [[((AppDelegate *)[[UIApplication sharedApplication] delegate]).viewController.webView stringByEvaluatingJavaScriptFromString:@"document.getElementById(\"myCustomDiv\").offsetTop;"] intValue];
int textFieldContainerXOffset = [[((AppDelegate *)[[UIApplication sharedApplication] delegate]).viewController.webView stringByEvaluatingJavaScriptFromString:@"document.getElementById(\"myCustomDiv\").offsetLeft;"] intValue];
UITextField *myTextField = [[UITextField alloc] initWithFrame: CGRectMake(textFieldContainerXOffset, textFieldContainerYOffset, textFieldContainerWidthOutput, textFieldContainerHeightOutput)];
[((AppDelegate *)[[UIApplication sharedApplication] delegate]).viewController.webView addSubview:myTextField];
myTextField.delegate = self;
CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString: @"ok"];
[self writeJavascript:[pluginResult toSuccessCallbackString:self.callbackID]];
}
-(BOOL)textFieldShouldReturn:(UITextField *)textField
{
//here you create your request to the server
return NO;
}
-(BOOL)textFieldDidEndEditing:(UITextField *)textField
{
//here you create your request to the server
return NO;
}
@end
javascript
var keyboardHelper = {
showKeyboard: function(types, success, fail) {
return Cordova.exec(success, fail, "keyboardHelper", "showKeyboard", types);
}
};
You can get the coordinates for the input field using javascript on the webView. Then, place your own textField right on top of it and in it's delegate method textFieldShouldReturn send a request to the server with the code the user typed in.
//Get text field coordinate from webview. - You should do this after the webview gets loaded
//myCustomDiv is a div in the html that contains the textField.
int textFieldContainerHeightOutput = [[webView stringByEvaluatingJavaScriptFromString:@"document.getElementById(\"myCustomDiv\").offsetHeight;"] intValue];
int textFieldContainerWidthOutput = [[webView stringByEvaluatingJavaScriptFromString:@"document.getElementById(\"myCustomDiv\").offsetWidth;"] intValue];
int textFieldContainerYOffset = [[webView stringByEvaluatingJavaScriptFromString:@"document.getElementById(\"myCustomDiv\").offsetTop;"] intValue];
int textFieldContainerXOffset = [[webView stringByEvaluatingJavaScriptFromString:@"document.getElementById(\"myCustomDiv\").offsetLeft;"] intValue];
myTextField.frame = CGRectMake(textFieldContainerXOffset, textFieldContainerYOffset, textFieldContainerWidthOutput, textFieldContainerHeightOutput);
[webView addSubview:myTextField];
myTextField.delegate = self;
Then you implement textFieldShouldReturn and create your request to the server there.
-(BOOL)textFieldShouldReturn:(UITextField *)textField
{
//here you create your request to the server
return NO;
}
This is done in existing project, however without using PhoneGap. I hope you can adapt it to suit your needs.
To remove the text field, you can hide it
myTextField.hidden = YES;
or
myTextField = nil;
or
[myTextField removeFromSuperView];