Braintree-web: Hosted Fields Instance focus is not working properly on iOS Safari

Created on 4 Dec 2018  路  8Comments  路  Source: braintree/braintree-web

General information

  • SDK version: 3.39.0
  • Environment: Sandbox and Production
  • Browser and OS: Mozilla/5.0 (iPhone; CPU iPhone OS 12_0_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0 Mobile/15E148 Safari/604.1 on iOS - iPhone 8 plus

Issue description

Hi,
we are trying to implement an automatic focus change to next field for Credit Card fields. What we are trying to accomplish here is that when the user fills out the credit card number filed and it is determined as valid it immediately changes the focus field to next one (ex. date, then from date to CVV).
We have successfully accomplished that on desktop browsers by using these lines of code:

Calling a function makeFieldValid() on validity change:

hostedFieldsInstance.on('validityChange', function(event) {
    var field = event.fields[event.emittedBy];

    if (!field.isValid && !field.isPotentiallyValid) {
        // Case when there is an error
        makeFieldInvalid(event.emittedBy);
    } else if (!field.isValid && field.isPotentiallyValid) {
        // Case when it's neutral
        makeFieldNeutral(event.emittedBy);
    } else {
        // Case when it's valid
        makeFieldValid(event.emittedBy);
    }
});

makeFieldValid() function sets focus to next field if determined as valid:

function makeFieldValid(field) {
    var $fieldContainer = $(hostedFieldsInstance.getState().fields[field].container);

    $fieldContainer.next().html(getFieldLabel(field));
    $fieldContainer.next().css('color', 'green');
    $fieldContainer.css('border', '1px solid green');

    if (field == 'number') {
            hostedFieldsInstance.focus('expirationDate');
    } else if (field == 'expirationDate') {
            hostedFieldsInstance.focus('cvv');
    }
}

And here鈥檚 the on focus function for hosted field:

hostedFieldsInstance.on('focus', function(event) {
    var field = event.fields[event.emittedBy];
    $(field.container).next().addClass('focus');
});

While this code works as expected on desktop browsers (Chrome, Safari, Opera etc.), there is a problem on Mobile Safari with this. When hostedFieldsInstance.focus is called the focus field is not changed although the on focus function is still called which can be seen when the field label changes its position (see attachment) and also testing with breakpoints in dev console shows the same.

Steps to reproduce the issue. ( Assuming that the order of fields is: number, exp. date, CVV )

  1. On credit card hosted fields click inside exp. date field and type 2 chars.
  2. Delete chars so the field is empty
  3. Click in the CC Number field and Write a valid CC number
  4. When it鈥檚 asserted as valid it should change focus to the next hosted field. But it鈥檚 not.

If the user is filling out the Credit card field as first it works as expected. Although if the user gets back to the field and changes something it does not work the second time anymore.

Hope you will be able to look into this issue.

Thanks,
Em墨ls

Most helpful comment

Just did some testing, and that looks like it did the trick. Aiming to get this out in a release next week.

Thanks @lgodziejewski !

All 8 comments

In mobile safari, only touch events are allowed to open the keyboard, so you cannot programmatically change the focus to the new input. This is built into mobile Safari and there are no workarounds that I am aware of.

See the example here with some information about quirks with the focus behavior in certain browsers: https://braintree.github.io/braintree-web/current/HostedFields.html#focus

Hi, it's not quite the thing you have described. The keyboard is already opened and we are just changing the field focus. It is working correctly on first time but something breaks on changing hosted fields on second time.
Another screenshot here

Ahh, that is another known issue with iOS iframes.

Basically, the gist is that when an input inside an iframe loses focus, internally, it has no idea that it has lost focus. So when it is focussed again, it doesn't bring up the keyboard because it thinks it is already in focus (and therefore the keyboard is visible). Tapping the input again should bring up the keyboard.

This is, much to my chagrin, a bug in iOS Safari without a good workaround.

https://forums.developer.apple.com/thread/28656 <- from 2015!

https://stackoverflow.com/questions/47100321/on-any-ios-mobile-devices-inputs-within-iframes-have-issues-determining-when-in

Please report this behavior to Apple (https://www.apple.com/feedback/safari.html). We already have, but there has been no action on the bug for many iOS versions. :(

Thank you for looking into this!

If someone is interested, then our current workaround for this issue is setting a flag variable that checks if the field has been in focus state. If it hasn鈥檛, only then, we programmatically change the focus to the next field. It works OK if it鈥檚 the first time and only if the user is in focus state the second time it starts to break.

@crookedneighbor I've found a workaround proposal that has to be put inside the iframe (so unfortunately we can't do it from the parent page)

https://github.com/ftlabs/fastclick/issues/37#issuecomment-355235805

maybe worth a try?

Just did some testing, and that looks like it did the trick. Aiming to get this out in a release next week.

Thanks @lgodziejewski !

This is fixed in 3.42.0, thanks again @lgodziejewski !

Great! I can confirm this has fixed our issues on iOS in our Cordova app

Was this page helpful?
0 / 5 - 0 ratings