xmaestro / angular2-recaptcha

Angular 2 : Typescript component for Google reCaptcha
ISC License
79 stars 30 forks source link

All text input controls disabled in IE11 after removing reCAPTCHA with ngIf #61

Closed BeheadedKamikaze closed 7 years ago

BeheadedKamikaze commented 7 years ago

I was looking into this strange behaviour when I found this article: Textbox occasionally gets disabled on IE11 and I believe they are related.

It seems to occur when reCAPTCHA pops up its image picker (which is in an IFRAME) and the user chooses correctly (placing focus into the IFRAME), then clicks on a 'Next' button on the UI, wherein there is logic that causes Angular to destroy the DOM node containing it due to an *ngIf on a parent container - imagine this as the first step in a wizard or tabbed-navigation interface.

It seems that possibly the DOM is being destroyed basically during the mouseup event of the button, thereby not fully migrating focus away from the IFRAME. Then when it is destroyed, the browser bug triggers and no text boxes are focusable anymore. Well, you can click on them but no cursor appears and typing into them is disabled.

The problem does not occur if you were to click into a text box before clicking the 'Next' form button (focus is pulled out of the IFRAME).

We might need a way to refocus the container in the ngOnDestroy event... I will look into it but I'm posting this here to keep a record of it (and hopefully help anyone else who might be experiencing this issue).

xmaestro commented 7 years ago

Any updates regarding this?

BeheadedKamikaze commented 7 years ago

I'm not sure if it can be solved purely by this component, without requiring additional effort on the part of the consumer. To grab the focus back from the iframe, you need to call .focus() on a focusable element - an input, anchor, button, textarea, img with map links, etc. or an element with an explicit tabindex. Any old div just doesn't work.

It would also be preferable to try to maintain the tab order, i.e. not just reset the focus to the body or first focusable element on the page, as this would destroy usability for keyboard users.

As I see it there are 2 viable options... 1 (the option that we went with) is to require the consumer to take responsibility for ensuring a known element on the page has focus, at some point after the token is received, but before the reCAPTCHA is removed from the page. So in our button (click) handler we explicitly focus the submit button (using an ElementRef), then use a setTimeout to toggle the flag bound to the *ngIf on the reCAPTCHA, ensuring that the button will have focus before this component is destroyed.

A second option might be to add some API to this component where you could pass an ElementRef (or maybe a CSS selector?) and it would attempt to push focus to that element from ngOnDestroy. I'm not 100% sold on this but I could be convinced if there was demand for it.

BeheadedKamikaze commented 7 years ago

As my use case is solved I am happy if you want to close this issue.

However as I said, if others are experiencing the same problem and are interested in my second option, try to convince me and I might make a PR ;)

xmaestro commented 7 years ago

Thanks @BeheadedKamikaze . Let's come back to this one if it comes up again.