Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fires click when stop scroll with tap/click #1438

Closed
juliancesar opened this issue May 19, 2014 · 17 comments
Closed

Fires click when stop scroll with tap/click #1438

juliancesar opened this issue May 19, 2014 · 17 comments
Assignees
Milestone

Comments

@juliancesar
Copy link

The default behavior is only stop scroll, but in ionic the scroll stops and fires the click.
Someone else with same problem?

iOS 7.1.1
iPhone 5
Ionic 1.0.0-beta.b5

@juliancesar juliancesar changed the title Fire click when stop scroll with tap/click Fires click when stop scroll with tap/click May 19, 2014
@adamdbradley
Copy link
Contributor

Can you explain a little more about how we can replicate the issue?

@juliancesar
Copy link
Author

Yes, follow this steps:

1 - Scroll the list scrolling down taking out your finger off the screen (long scroll)
2 - Try stop the scrolling with a tap on element that has a ng-click

@juliancesar
Copy link
Author

The default behavior is only stop de scroll, but today (b5) ionic stops the scroll and fires a click event!

@perrygovier
Copy link
Contributor

Hey @AdamBradley, here's an example http://codepen.io/perrygovier/pen/ntibg
Just scroll and then click to stop the scroll. A reference for the desired behavior could be the address book on ios.

Note, I'm seeing this on mobile and desktop.

@juliancesar
Copy link
Author

@adamdbradley, i'm waiting only this issue for publish my first app on App Store, can you help me?

@juliancesar
Copy link
Author

I made a work around, maybe this help to solve this issue.

My ion-content:

on-scroll="scrollList()"

My Controller:

$scope.lastScrolling = new Date().getTime();

$scope.scrollList = function() {
    $scope.lastScrolling = new Date().getTime();
};

$scope.canClickInList = function() {
    var diff =  new Date().getTime() - $scope.lastScrolling;
    if (diff > 200) {
        return true;
    } else {
        return false;
    }
};

And finally, in my function to click above item in controller:

if ($scope.canClickInList()) {
    // ACTION
}

@insectean
Copy link

I also wanted to solve this issue, which still exists for iOS 8.0.2 in 1.0.0-beta.13, but I made a slightly different workaround, inspired by @juliancesar's but without all the new Date().getTime() calls.

My ion-content:

on-scroll="incrementScrollCount()" on-scroll-complete="resetScrollCount()"

My controller:

var scrollCount = 0, prevScrollCount = 0;

$scope.incrementScrollCount = function() {
    scrollCount += 1;
}

$scope.resetScrollCount = function() {
    prevScrollCount = scrollCount;
    scrollCount = 0;
}

In my ng-click function:

if (prevScrollCount <= 1) {
    // ACTION
}

It seems to work because only one on-scroll call is made between the on-scroll-complete call and the ng-click call when the user taps once without swiping, but I'd prefer something nicer and more stable, if possible. This behavior is common among native iOS apps (one example being Settings on an iPad), so I would expect users to expect it in mine.

@insectean
Copy link

An update: It turns out my solution is unreliable since no specific order is guaranteed for the various callbacks, and in fact on-scroll-complete is not even guaranteed to fire when the user stops the scrolling with a tap. (I suppose nothing at all is guaranteed about on-scroll-complete since it isn't mentioned in the documentation.)

Instead, I'm now using a solution much like @juliancesar's but using Date.now() instead of new Date().getTime, which I recommend for potentially better performance (according to this jsPerf, for instance).

I would still like a vanilla solution, please!

@alidawud
Copy link

+1

@alidawud
Copy link

Hello guys, I found a solution by editing "ionic.bundle.js"

  1. Search for if condition: if (self.__isDecelerating), which inside doTouchStart: function(touches, timeStamp)
  2. Add: try{ ionic.Gestures.detection.stopDetect();}catch(e){}

*I use "on-tap" directives to handle click events.
*tested in IOS and Chrome.
*using 1.0.0-beta.14-nightly-924

@adamdbradley
Copy link
Contributor

related: #2665

@Shadowstep33
Copy link

Shadowstep33 commented Nov 10, 2016

This is actually still happening for me with ionic 1.7.7

I am using a directive for the scrollable list with something that looks like this:

    <ion-list class="item-list {{ theme + '-theme' }}" scroll="true">
        <ion-item class="item calendar-list-item item-remove-animate col-xs-12 no-padding {{event.type}}" ng-repeat="(k,event) in tasks track by $index | orderObjectByTwoProps: 'plan_item':'time'" ng-if="(!filter || filter.indexOf(event.type) >= 0)" on-tap="toggleTask(event)">

            <div class="handler col-xs-12 no-padding" ng-if="event.type == 'workout'" ui-sref="app.workouts({ id: {{event.id}}, fromCalendar: true, eventID: {{ event.eventID }}, calendarDay: {{ k }} })">

                <div class="col-xs-8 blue-border-right" style="height: 100%;">
                    <div class="col-xs-2" on-tap="logWorkout(event)" ion-stop-event="click">
                        <div ng-class="(event.completed ? 'complete' : '') + ' complete-block ' + event.type"></div>
                    </div>
                    <div class="col-xs-10">
                        <h2 class="light">{{ event.title }}</h2>
                        <span class=" sublabel light pale-blue">{{ event.description }}</span>
                    </div>
                </div>
                <div class="col-xs-4">
                    <h1 class="light hours">--</h1>
                </div>

                <ion-option-button class="button-assertive icon-left ion-trash-b blue-bg" on-tap="$ionicListDelegate.closeOptionButtons();removeFromSchedule(event)"></ion-option-button>

            </div>
...

@chrisyuyangshen
Copy link

chrisyuyangshen commented Dec 21, 2016

This issue still exists on my app, although it's working as expected on PC (with ionic serve). I'm using ionic 2.0. @adamdbradley see the demo http://codepen.io/chrisyuyangshen/pen/BQEzNj

@EmreErdogan
Copy link

EmreErdogan commented Mar 10, 2017

@juliancesar your solution works well.
@insectean your replacement of new Date().getTime() with Date.now() improves the performance.

Thank you all.

I wonder if any of you guys or other fellows can convert this solution into a directive, so that we don't anymore need to copy paste the calculation logic and the click event handler into every controller where this solution is going to be used. Also the view may become cleaner if on-scroll and ng-click directive calls are removed. To sum up, what I am looking for is a single directive that can be attached to ion-content that wraps up all of those logic and handles clicks while scrolling.

For example:

<ion-content prevent-click-on-scroll>

where prevent-click-on-scroll is the directive I am looking for.

@cweidinger
Copy link

cweidinger commented Apr 10, 2017

+1 This issue still exists for me on ios using the latest ionic2.

@EmreErdogan
Copy link

EmreErdogan commented Apr 12, 2017

I modified the code of @juliancesar and @insectean, then moved it to a service called ScrollClickHandler. I tested it in my project and it works fine. Here's the implementation:

.service("ScrollClickHandler", function(){

  var lastScrolling = Date.now();

  var scrollList = function(){
    lastScrolling = Date.now();
  };

  var canClickInList = function() {
    var diff = Date.now() - lastScrolling;
    if (diff > 200) {
      return true;
    }
    return false;
  };

  this.getScrollHandler = function(){
    return scrollList;
  };

  this.getClickHandler = function(callbackFunc){
    return function(clickEvent){
      if(!canClickInList()){
        clickEvent.preventDefault();
        clickEvent.stopPropagation();
        console.log('cannot click');
      } else {
        if(typeof callbackFunc === 'function'){
          callbackFunc.apply(this, arguments);
        }
        console.log('can click');
      }
    };
  };

})

Now, after injecting ScrollClickHandler into your controller as a dependency you can use it like this.

In your controller:

.controller('MyController', ['$scope', 'ScrollClickHandler', function($scope, ScrollClickHandler){
  $scope.scrollHandler = ScrollClickHandler.getScrollHandler();
  $scope.clickHandler = ScrollClickHandler.getClickHandler();

  // other stuff
}]);

And in your ion-content and ion-list:

<ion-content on-scroll="scrollHandler()">
    <ion-list>
        <ion-item ng-repeat="thing in things" ng-click="clickHandler($event)"> ... </ion-item>
    </ion-list>
</ion-content>

That's it!

Note: Optionally, you can pass a callback function to the getClickHandler method to be called when the user clicks on an item. Example:

$scope.clickHandler = ScrollClickHandler.getClickHandler(function(e, idx){
    console.log("User has clicked the item at index: " + idx);
});

And

<ion-item ng-repeat="thing in things" ng-click="clickHandler($event, $index)"> ... </ion-item>

@ionitron-bot
Copy link

ionitron-bot bot commented Sep 3, 2018

Thanks for the issue! This issue is being locked to prevent comments that are not relevant to the original issue. If this is still an issue with the latest version of Ionic, please create a new issue and ensure the template is fully filled out.

@ionitron-bot ionitron-bot bot locked and limited conversation to collaborators Sep 3, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants