Category Archives: mobile

Formatting Credit Card Numbers – Dealing with Webkit Text Input Oddity

27 Apr 2012

Another day, another script added to my library…. I had a credit card text field in one of my Sencha Touch projects that needed to be “dash separated” while the person is typing. Below is my solution to this particular minor challenge. Please remove any other validation in your project as this already features:

  • Removal of all undesired alpha characters and symbols
  • Limited to a maximum of 16 numbers
  • Plays nice when you backspace from the end

Note that you shouldn’t try to correct a number in the middle of the string – if you delete a number the entire string gets re-written for the current string of numbers. Also, the first thing that may come to mind is the HTML 5 “pattern” attribute which accepts a regular expression with which to validate the text field value, however, that would validate as you type, not format the string in the desired manner while the typing is happening. Sencha has its own way of validating text fields which is essentially the same thing but the issue is that it also doesn’t do on-the-fly string formatting.

So here is the function itself, which works perfectly in a normal web-browser (yes, a caveat for android webkit follows):

...
    function do_ccFormat(str){
	var nums = str.substr(0,19).replace(/[^\d]/gi,'');
	var r = nums.match(/(\d){4}/g);
	if (r){	
	    var i=0, nStr = '';
	    for (;i

However, in Android 2.3.6's webkit there is some odd behavior that is a pattern that I'm sure others somewhere have come up against. So the pattern is this: first assume that you are doing some string manipulation on the keyup event, waiting for some criteria to be met at every key stroke before manipulating the string. In the case of my CC formatter its the 5th character that triggers the string re-write. So lets say you type 5 characters such as "12345". When "5" is typed the entire string is replaced with a new one that contains a new character/delimiter - like so: "1234-5". The very next character that you type will not go at the end where the cursor is but before the last character that was entered. So if we enter "6" the string ends up like this: "1234-65". Further, if you hit the backspace key you backup not from the cursor position (which is at the end of the string) but from where the last character was erroneously entered! Weird stuff! This gets worse with every new delimiter that is added to the string.

Upon inspection and some thought, I realize that replacing the value with a formatted value as you type is something that the Android 2.x webkit can't handle when it has to then figure out where the cursor should go. It seems that programatically setting the value does not update the cursor position for the field - it stays where it is. If you pay close attention when all this happens you'll notice that the cursor will quickly jump around.

I then hit upon the idea of blurring the field (thinking to therefore dump whatever erroneous machinations may be at play) and then quickly give focus back to it knowing that the act of giving focus to a field sets the cursor to the end. This works as long as you space out the blur/focus methods with a setTimeout. I spaced them out by 100 milliseconds hoping that the soft keyboard wouldn't flash. This appeared to work well Android 2.3.6 (a Samsung Galaxy S2). The keyboard would just sit there apparently none-the-wiser.

While this did seem to work it turned out to be unpredictable. In Android 2.2 the keyboard would go away and not reappear, sometimes that would happen in 2.3.6, and it does go away in Android 3.

Its unfortunate that this doesn't work in pre-ICS Android - it is what it is. Below is how I implemented it in Sencha Touch 1 - as you can see I apply it on keyup for iOS and ICS for as-you-type formatting. For pre-ICS Android I limit the keyed cc number length to a max of 16 characters and apply CC formater when the CC field is blurred (a length of 19 is needed otherwise since we are adding 3 additional characters in the form of the "-" delimiter).

I should end by saying that this obviously does not include a MOD10 check. I'll toss in my MOD10 checker at a later date as a separate article - it will include the ability to check not only entire cc numbers - which all of the readily available MOD10 checkers do - but it will also allow you to check a CC number for its **type** based on the first four digits. Until then, here's Credit Card String Formatter sample implementation:

...
items:[
  {
    xtype:'textfield',
    name:'cardNumber',
    inputType:'tel',
    maxLength:'19',//allow the 3 dashes needed to format the string to be included
    listeners:{
	keyup:function(o,e){
            if (Ext.is.iOS || (Ext.is.Android && Ext.is.AndroidVersion > 3)){
	        o.setValue(do_ccFormat(o.getValue()));
            } else { // assume old android
                o.setValue(o.setValue().substr(0,16));
            }
	},
        blur:function(o,e){
            if (Ext.is.Android && Ext.is.AndroidVersion < 3){
               o.setValue(o.setValue().substr(0,16));
               o.setValue(do_ccFormat(o.getValue()));
            }
        }
    }
  }
]
...

Solving “The connection to the server was unsuccessful” Error in Android/PhoneGap

10 Apr 2012

At some point in time you will always have to update your dev environment – and inevitably when doing so you will find that you can’t compile your apps any more for any sort of a number of reasons – doesn’t matter if its iOS or Android (though I find its much, much more common on iOS). Well, today I’ve updated my Android SDK since I’d like for the first time ever to be able to use the AVD as Google has improved performance in that area. However, upon compiling one of my apps I have run into this error:

...
04-10 10:46:13.672: I/System.out(4057): onReceivedError: Error code=-6 Description=The connection to the server was unsuccessful. URL=file:///android_asset/www/index.html
...

This can be solved by adding a line to your main activity.java file:

...
super.setIntegerProperty("loadUrlTimeoutValue", 7000);
...

The timeout value itself is arbitrary, here I have it at 7 seconds. Adding this one line above the super.loadUrl resolves the “Connection to the server was unsuccessful” error.

Also, check to make sure that any remote scripts such as those being delivered to the app from a server are accessible. Sometimes I forget to remove the remote debugger from a project and find that this error will appear because the script cannot be downloaded – in that case you see the error message appear while the app loads behind it. So, check your script tags for remotely loading scripts and remove any hooks to remote debuggers/testing servers. You should also download copies of javascript libraries and keep them within your app to remove or at least reduce the chances of this error appearing.

Prevent PhoneGap UIWebView Bounce in iOS

14 Mar 2012

Here’s a quick one – sometimes your html5 app will for whatever reason cause the UIWebView to break out of PhoneGap’s bounce-less restrictions (for lack of a better way to describe it). This will resolve the issue – in Xcode, look for your AppDelegate.m file, located within the Classes directory. Open that up and look for the function called:

...
 (void)webViewDidFinishLoad:(UIWebView *)theWebView
...

Within the curly braces paste the following line:

...
[[theWebView.subviews objectAtIndex:0] setBounces:NO]; 
...

[edit…]

The ability to control bounce has moved to the config.xml file – there may be multiples of this file within your PhoneGap project so if editing one doesn’t seem to do anything you’ve got the wrong file – do a search for the other one.

Within the config.xml add this node:

Changing Target Android Version in Eclipse

12 Mar 2012

This one takes care of the “Attribute minSdkVersion(x) is lower that the project target API level(x)” error that you may encounter if attmpeting to change your app’s Android target version after having setup your Eclipse project for Phonegap. The error manifests itself as a build error with this the following description (which illustrates a target of 8 being below the projects API level of 10):

To change the target Android API level you need to do two things:

  1. Update the Android Manifest
  2. Update the App Target API Level

See this page for more information on Build Targets and
acceptable values: Android API Level Guide.

First go to your project folder in Eclipse. In the root you should find a file called “AndroidManifest.xml“. Double-click this file. Eclipse will either show you the UI view of the XML document, which looks like this:

Or Eclipse may show you the manifest in source view which would look like this:

In the UI view of the manifest you are looking for the “Min SDK version” filed – set that to the desired SDK version that you want to target. Save the change and then close the manifest. If you cannot locate the Min SDK Version then look under “Manifest Extras” and click on “Uses SDK” – the desired field will appear to the right under the “Attributes for Uses SDK” heading.

If you see the source-code view for the manifest then look for this line:

...

...

… and simply change the number (“8” in the above example) to whichever target API Level that you’re going for.

Next, you need to change the Project Build Target. To do so you will locate the root of your project within the Project Explorer (this appears as a directory tree structure), right click the app project root and select “Properties“. You will see the properties panel which looks like this:

At this point simply select the proper build target, apply and close.

Sencha Touch: Adding/Removing Asterisk in Required Fields

08 Mar 2012

Another day, another thing learned. Today its those little asterisk’s that appear next to the labels of required fields in Sencha Touch 1. You can set them so that they appear when the component is instantiated via the “required” config option but there is no method to add or remove them after the fact. Also, if you are building your Sencha app the old non-mvc way that means that no components are not being destroyed/created as needed, so you can’t set the value for “required” to be an expression (i.e., something ? true : false) because if you do it will only work once – when the component is created.

Looking at the html that Sencha produces I see that a class is added to the component that is responsible for the appearance of the asterisk. Since Sencha does provide a method to add/remove classes the solution couldn’t be simpler:

...
// too add the asterisk to the form element refer to its div and:
Ext.getCmp('id_of_field').addCls('x-field-required');
// to remove the asterisk from the form element:
Ext.getCmp('id_of_field').removeCls('x-field-required');
...

Keep in mind that this is just a visual thing – no matter how you set the component’s “required” property there is no impact on any form validation.