Skip to content
This repository has been archived by the owner on May 29, 2019. It is now read-only.

$modal + ngTouch input issues on iOS/Android #2280

Closed
ijlind opened this issue May 30, 2014 · 25 comments
Closed

$modal + ngTouch input issues on iOS/Android #2280

ijlind opened this issue May 30, 2014 · 25 comments

Comments

@ijlind
Copy link

ijlind commented May 30, 2014

There is a weird issue with modal windows containing input fields on iOS and Android if ngTouch is used. For some reason, you can only focus on an input field with a long touch gesture. A regular touch gesture won't focus on the field (and thus won't open the virtual keyboard). On desktop browsers the issue does not exist but it also seems to work as it should on Mobile IE (WP8).

Here's a plunkr demonstrating the issue: http://plnkr.co/edit/X95ZBUd6FK2I2R14e3Lr?p=preview

@pablocespedes
Copy link

I'm also having this exact same issue.

@pedubreuil
Copy link

I'm having the same problem. Any update about this issue?

@pedubreuil
Copy link

Might be related to this issue: #2017

@pedubreuil
Copy link

I confirm, this seems to be a bug of ngTouch...
See this input blur() done here on the event "touchend" : https://github.com/angular/angular.js/blob/master/src/ngTouch/directive/ngClick.js#L256
The only solution I found is to write:

<div class="modal-body" >
   <input type="text" ng-click="getFocus()" />
</div>

with

scope.getFocus(){
   .....find('input')[0].focus();
}

@angi-
Copy link

angi- commented Sep 1, 2014

I am having the same issue, monkey patching the library is not an option for me. Any other ways to focus from controller for example?

@jbielick
Copy link

jbielick commented Sep 5, 2014

Hello all,

The issue mainly boils down to the modal template having an ngClick directive on the modal window itself. I couldn't tell you why this is necessary. In the angular-foundation package, which shares almost exactly the same html for the modal template, the ng-click="close($event)" doesn't map to anything at all. It's scope holds no close property or function.

Essentially what's happening here is:
1.) you tap on an input inside of a modal (basically a div with an ng-click directive)
2.) the parent modal window's ngClick directive detects a touchstart event
3.) ngTouch records the coordinates at which the touchstart occurred so that it can clickbust the the resulting click event that will fire afterwards naturally.
4.) touchend fires and ngTouch reconciles the ending point of your touch with where it began and determines that if a click event fires in the same spot, it'll bust it.
5.) a click event fires on the x and y coordinates where you touched (the input) and ngTouch clickbusts this event since it isn't "allowed". Clickbusting involves e.preventDefault(), e.stopPropagation() and event.target.blur() as seen on https://github.com/angular/angular.js/blob/master/src/ngTouch/directive/ngClick.js#L161

Some have found that commenting line 161 will resolve this, but probably precludes other desired functionality that line was intended for. Obviously, modifying an angular package isn't ideal. In my case, we ended up removing the module altogether. This probably can also be alleviated by removing the ng-click directive from the modal window itself. Can anyone comment on why the modal window has an ng-click directive?

See this plunker for a distilled case of this issue. Make sure you "emulate touch screen" from the chrome (or other) dev tools.

@sean-stanley
Copy link

I discovered this issue today and found the solution that best worked for me was removing ng-click="close($event)" from the modal window template. The functionality that was lossed was that clicking outside the modal no longer closes the modal. This was an acceptable loss in my application so this was the stablest and easiest way to resolve the issue as ngTouch was essential for other features like our image crop box.

I wonder if there's a way though to have the ng-click event put on the template for the modal backdrop as that is visually what the user clicks.

@chrisirhc
Copy link
Contributor

Excellent explanation and investigation, @jbielick .

From what I see here, the simplest way to resolve this is to bind the click event manually using $modalElm.on on the modal element in JavaScript instead of using ng-click in the template. That should solve this issue as the ngTouch module is only affecting the ngClick directive. PRs are welcome.

@jiniguez
Copy link
Contributor

jiniguez commented Dec 3, 2014

I also found this problem and solved it removing ng-click directive from template and binding a click event in the modal-window directive code. Not sure if this could break some other stuff but tests are ok and my project seems to be working ok with this fix.

I've created PR #3044 in case you think it's a good solution.

@liadlivnat
Copy link

I'm not sure it solves the issue 100%, when i open the modal it did let me enter a text, but when i closed the modal and re-open it, the bug is there again.

@tomasreichmann
Copy link

removing ng-touch from .modal solved the problem for me as well. You can't just move it to the backdrop, because the .modal covers entire viewport and .modal-backdrop is actualy behind .modal and can't be clicked.

I saw somewhere else people solved it by stopping event propagation on .modal-body but I didn't manage to make it work for me.

What is the event that busts the click called? I have zero experience with event propagation, can someone look into it? I guess this would help a lot of people.

@karianna karianna modified the milestones: 0.13, Backlog Jan 8, 2015
@karianna
Copy link
Contributor

karianna commented Jan 8, 2015

Fixed via #3044

@karianna karianna closed this as completed Jan 8, 2015
@liadlivnat
Copy link

HI, how can i get the latest fixed?

is it merged already to the master branch?

@antoinepairet
Copy link

@liadlivnat This fix is included in master.

@liadlivnat
Copy link

@antoinepairet when i'm doing bower update angular-ui-bootstrap i get Version: 0.11.2 - 2014-09-26, how can i get this version?

@memolog
Copy link

memolog commented Jun 24, 2015

@chrisirhc I'd like to know how the fix is going. I'm sorry to bother you, but it is essential for our product.

@piotrd
Copy link

piotrd commented Jul 2, 2015

@chrisirhc see here #3044 (comment). The fix apparently was merged and then reverted due to "not following merging guidelines" and has been forgotten since :(

@vdeturckheim
Copy link

Hi, is there any news regarding the re-merging of the fix?

Thanks a lot.

@adgoncal
Copy link

adgoncal commented Jul 8, 2015

+1

This is a very annoying bug.

@vdeturckheim
Copy link

BTW:
@jdhiro's fix worked for me!

@twhamilton
Copy link

+1 Why has this not been released. It is clearly a serious pain for everyone

@sean-stanley
Copy link

I had this issue but it took me an embarassingly long time to realise I had it. The directive approach did fix this issue for me though since I use ngTouch in other parts of my UI. I suppose another approach would be divide the portions using ngTouch into a seperate module and just have that module depend on ngTouch. That might mean ngTouch won't interfere with modals.

A PR solution could look like the directive provided though really the angularjs team should fix this one. The issue is scheduled to be fixed in either angularjs 1.4.x or 1.5.x so we might have to wait a while for them.

Fixing it ourselves here would help other people having the problem and not knowing about it or who can't wait on a new version of angularjs.

@ximon
Copy link

ximon commented Aug 20, 2015

This issue also affects selects on modals (see plunker http://plnkr.co/edit/2phDw62EVl1z9egd8EkA?p=preview) @jdhiro's fix #2017 (comment) gets around this issue too.

Having the modal in a separate module doesn't get around this issue unfortunately.

@entrity
Copy link

entrity commented Aug 26, 2015

👍

@rbalicki2
Copy link

The following fixed the issue for me. My best guess is that the clicks are continuing to propagate, and eventually result in the modal getting focus, but I have not confirmed that hypothesis:

(function() {
  angular.module('someModule')
    .directive('input', [
      function() {
        return {
          restrict: 'E',
          link: link
        };
      }
    ]);

  angular.module('someModule')
    .directive('textarea', [
      function() {
        return {
          restrict: 'E',
          link: link
        };
      }
    ]);

  function link(scope, elem) {
    // bind the events iff this is an input/textarea within a modal
    if (elem.parents('.modal').length) {
      elem.on('touchstart', function(e) {
        elem.focus();
        e.preventDefault();
        e.stopPropagation();
      });
    }
  }
})();

I did not test whether both preventDefault and stopPropagation were necessary, as I assume I'll remove these directives when it's patched in ngTouch / angular / angular-ui-bootstrap :)

chrisirhc pushed a commit to chrisirhc/angular-ui-bootstrap that referenced this issue Sep 7, 2015
- Merge pull request angular-ui#3044 from jiniguez/fix2280
Conflicts:
	src/modal/modal.js
	template/modal/window.html

Fixes angular-ui#2280
chrisirhc pushed a commit to chrisirhc/angular-ui-bootstrap that referenced this issue Sep 7, 2015
- Merge pull request angular-ui#3044 from jiniguez/fix2280
Conflicts:
	src/modal/modal.js
	template/modal/window.html

Fixes angular-ui#2280
jasonaden pushed a commit to deskfed/bootstrap that referenced this issue Jan 8, 2016
- Merge pull request angular-ui#3044 from jiniguez/fix2280
Conflicts:
	src/modal/modal.js
	template/modal/window.html

Fixes angular-ui#2280
Closes angular-ui#4357
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.