Skip to content

Loading…

Action helper click events don't fire on touch devices #605

Closed
ebryn opened this Issue · 12 comments
@ebryn
Ember.js member

No description provided.

@wagenet
Ember.js member

The events do fire, but only if the element is one that responds to click events. This is technically not a bug, but it's something we should improve.

@JamesHight

Here is a patch I'm using for handling click events on touch devices.
It may be a good starting point.

(function($){       
    var touch = {       
        start: false, // has the touchstart event been triggered and is it still a valid click event?
        // starting coordinates of touch event
        x: null, 
        y: null
    };

    Ember.EventDispatcher.reopen({
        setupHandler: function(rootElement, event, eventName) {
            var self = this;

            rootElement.delegate('.ember-view', event + '.ember', function(evt, triggeringManager) {        
                // Track touch events to see how far the user's finger has moved
                // If it is > 20 it will not trigger a click event
                switch(evt.type) {
                    // Remember our starting point
                    case 'touchstart':                  
                        touch.start = true;
                        touch.x = evt.originalEvent.touches[0].clientX;
                        touch.y = evt.originalEvent.touches[0].clientY;
                        break;

                    // Monitor touchmove in case the user moves their finger away and then back to the original starting point
                    case 'touchmove':
                        if (touch.start) {
                            var moved = Math.max(Math.abs(evt.originalEvent.touches[0].clientX - touch.x), 
                                            Math.abs(evt.originalEvent.touches[0].clientY - touch.y));
                            if (moved > 20)
                                touch.start = false;
                        }
                        break;

                    // Check end point
                    case 'touchend':
                        if (touch.start) {
                            var moved = Math.max(Math.abs(evt.originalEvent.changedTouches[0].clientX - touch.x), 
                                        Math.abs(evt.originalEvent.changedTouches[0].clientY - touch.y));
                            if (moved < 20) {
                                // Prevent touchend event so the simulated click event is not triggered
                                evt.preventDefault();           
                                // All tests have passed, trigger click event
                                $(evt.target).click();
                            }
                            touch.start = false;
                        }                           
                        break;
                }

                // END touch code

                var view = Ember.View.views[this.id],
                result = true, manager = null;

                manager = self._findNearestEventManager(view,eventName);

                if (manager && manager !== triggeringManager) {
                    result = self._dispatchEvent(manager, evt, eventName, view);
                } else if (view) {
                    result = self._bubbleEvent(view,evt,eventName);
                } else {
                    evt.stopPropagation();
                }

                return result;
            });

            rootElement.delegate('[data-ember-action]', event + '.ember', function(evt) {
                var actionId = Ember.$(evt.currentTarget).attr('data-ember-action'),
                    action   = Ember.Handlebars.ActionHelper.registeredActions[actionId],
                    handler  = action.handler;

                if (action.eventName === eventName) {
                    return handler(evt);
                }
            });
        }
    });

})(jQuery);
@krisselden
Ember.js member

see my comments in #586 for a much simpler solution

@tomdale
Ember.js member

For now, I think it's the responsibility of the application developer to make the element tappable on iOS devices. If you stick to links, this should work fine. If this is tripping people up, I'd accept a pull request adding additional documentation to the {{action}} helper.

@tomdale tomdale closed this
@ppcano ppcano referenced this issue in emberjs-addons/ember-touch
Open

Enable an easy way to map tapEnd event to click #12

@topfunky

This is painful, especially since it can be solved by adding a meaningless href to any link.

IMHO supporting iOS out of the box should be a value of this project.

Especially since it took several different Google searches to find this thread.

@demongloom

Agree with topfunky, we need a more convenient way to bind on both click and touch

@FoxGit

I also agree with @topfunky. Being able to test certain actions both on a desktop browser and an iPad would be really helpful.

@arcreative

I just found a wonderful fix by mistake. I'm doing most of my testing in Chrome before deploying to Android/iOS via PhoneGap. I opted for jquery mobile's touch implementation (using a custom build with ONLY touch enabled) because it seemed a little more simple to implement than ember-touch. I used the following to avoid unwanted double-click behavior due to the tap AND click events registering:

App = Ember.Application.extend({
    customEvents: {
        tap: "click",
        click: null //Prevent tap from registering as two clicks
    }
});

This registers the tap as a click and the click as nothing, so the double-click nonsense I was encountering using tap events is no longer an issue. It has the added advantage of working with the standard action helper as well on all platforms I'm using, so someone might want to give this a shot to see if it works. No more tapEnd or touchend to worry about, this has been a 100% perfect implementation for me so far.

This was originally in response to #586

@manufaktor

this little CSS hack has worked for me:

[data-ember-action] {
  cursor: pointer;
}
@elsurudo

@manufaktor Thanks for the quick fix, seems to be working nicely.

@tute tute added a commit to tute/website that referenced this issue
@tute tute Add documentation about `action` 9b8ea12
@tute tute referenced this issue in emberjs/website
Merged

Add documentation about `action` #1585

@tute tute added a commit to tute/website that referenced this issue
@tute tute Add documentation about `action` fbb3c6f
@ming-codes

Changing the tag to <button> seems to help. You can style the button to not look like a button.

@stefanpenner
Ember.js member

@lightblade just ensure the clickable entity has cursor: pointer; (this has nothing to do with ember but how touch devices trigger/simulate click events).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.