Search code examples
jqueryhtmlangularjsjquery-mobile

jQuery / AngularJS: Tap hold not working inside AngularJS


I'm open for suggestions as I am no good in AngularJS. I want to hide image box and get the id of image.

<div data-role="page" id="pageone">
    <div data-role="main" class="ui-content">
        <div class="my-gallery" itemscope id="grid"   >
            <div ng-repeat="imageUrl in images" class="col-xs-3">
                <p>
                    <figure itemprop="associatedMedia">
                        <a href="{{imageUrl}}" name="thumb" id="{{pid[$index]}}" class="thumbnail" itemprop="contentUrl"  data-size="800x600">
                            <img src="" class="img-responsive" id="{{pid[$index]}}" ng-src="{{thumb[$index]}}" style="min-height:50px;height:50px;">
                        </a>
                    </figure>
                    <p>Tap and hold me!</p>
                </p>
            </div>
        </div>
    </div>
</div>

and here is the js code to hide and get the id of image.

<script>
$(document).on("pagecreate","#pageone",function(){
  $("p").on("taphold",function(){
    $(this).hide();
  });                       
});
</script>

If i use above code in below form then it is working fine.

<div data-role="page" id="pageone">
    <div data-role="main" class="ui-content">
        <p>If you tap and hold me for one second, I will disappear.</p>
        <p>Tap and hold me!</p>
        <p>Tap and hold me too!</p>
    </div>
</div>

What am I trying to achieve is below. User can tap-hold on any image then an event get fired to delete the image from server. I'll execute HTTP request for that and later it will hide that image.

At the moment I'm not able to even it is not hiding. Looks like tap-hold event is not firing.


Solution

  • First of all you should take a look at this post "Thinking in AngularJS" if I have a jQuery background? which will help you to understand whats important by using AngularJS. Most users who came from jQuery doesnt realy understand how JavaScript and its asynchronism behaviors work. jQuery is mostly executed synchronously due to simple DOM manipulations. Its not a good way to mix jQuerywith AngularJS because jQuerymanipulate the DOM. And more important -> there is no need to mix jQuery with AngularJS.

    Using jQuery and AngularJS could break AngularJS. On the other hand jQuery is hard to use while its mostly using DOM manipulations and binding. In your case the data binding fails because the DOM was generated by AngularJS. Thats the main problem. Your p elements which you like to bind with on('taphold') are not available in DOM in the moment you bind it with jQuery. Thats why your binding fails.

    Please take a look at this Fiddle. It reproduces your problem. Hint, I replace the taphold event with click to make it work on non-mobile devices but this doesnt matter, the binding/problem is the same. So you can click remove the p finished rendering after document is ready event. The p elements which were rendered with AngularJS can't be removed because the jQuery data binding fails / was long before the element appeared / or the $scope changed and has been rerendered by AngularJS due to E2E databinding.


    The following example shows you how to bind events in AngularJS. This event is called longPress which is nearly the same as taphold. It should work for both mobile and desktop applications.

    Example Fiddle by using longPress directive:

    View

    <div ng-controller="MyCtrl">
      <div ng-repeat="image in images">
        <p ng-show="image.show" on-long-press="image.show = false">
          {{image.url}}
        </p>
      </div>
    </div>     
    

    AngularJS Application

    var myApp = angular.module('myApp',[]);
    
    myApp.controller('MyCtrl', ['$scope', '$timeout', function ($scope, $timeout) {
         $scope.images = [{
            show: true,
            url: 'some/url.jpg'
          },{
            show: true,
            url: 'some/url.jpg'
          },{
            show: true,
            url: 'some/url.jpg'
          }];
    }]);
    
    // taken from https://github.com/puneethrai/angular-long-press/blob/master/dist/angular-long-press.js
    myApp.directive('onLongPress', ['$parse', '$timeout', function ($parse, $timeout) {
        return {
            restrict: 'A',
            link: function ($scope, $elm, $attrs) {
                var timer;
                var timerDuration = (!isNaN($attrs.longPressDuration) && parseInt($attrs.longPressDuration)) || 600;
                // By default we prevent long press when user scrolls
                var preventLongPressOnScroll = ($attrs.preventOnscrolling ? $attrs.preventOnscrolling === 'true' : true)
                // Variable used to prevent long press while scrolling
                var touchStartY;
                var touchStartX;
                var MAX_DELTA = 15;
                // Bind touch, mouse and click event
                $elm.bind('touchstart', onEnter);
                $elm.bind('touchend', onExit);
    
                $elm.bind('mousedown', onEnter);
                $elm.bind('mouseup', onExit);
    
                $elm.bind('click', onClick);
                // For windows mobile browser
                $elm.bind('pointerdown', onEnter);
                $elm.bind('pointerup', onExit);
                if (preventLongPressOnScroll) {
                    // Bind touchmove so that we prevent long press when user is scrolling
                    $elm.bind('touchmove', onMove);
                }
    
                function onEnter(evt) {
                    var functionHandler = $parse($attrs.onLongPress);
                    // For tracking scrolling
                    if ((evt.originalEvent || evt).touches) {
                        touchStartY = (evt.originalEvent || evt).touches[0].screenY;
                        touchStartX = (evt.originalEvent || evt).touches[0].screenX;
                    }
                    //Cancel existing timer
                    $timeout.cancel(timer);
                    //To handle click event properly
                    $scope.longPressSent = false;
                    // We'll set a timeout for 600 ms for a long press
                    timer = $timeout(function () {
                        $scope.longPressSent = true;
                        // If the touchend event hasn't fired,
                        // apply the function given in on the element's on-long-press attribute
                        $scope.$apply(function () {
                            functionHandler($scope, {
                                $event: evt
                            });
                        });
                    }, timerDuration);
    
                }
    
                function onExit(evt) {
                    var functionHandler = $parse($attrs.onTouchEnd);
                    // Prevent the onLongPress event from firing
                    $timeout.cancel(timer);
                    // If there is an on-touch-end function attached to this element, apply it
                    if ($attrs.onTouchEnd) {
                        $scope.$apply(function () {
                            functionHandler($scope, {
                                $event: evt
                            });
                        });
                    }
    
                }
    
                function onClick(evt) {
                    //If long press is handled then prevent click
                    if ($scope.longPressSent && (!$attrs.preventClick || $attrs.preventClick === "true")) {
                        evt.preventDefault();
                        evt.stopPropagation();
                        evt.stopImmediatePropagation();
                    }
    
                }
    
                function onMove(evt) {
                    var yPosition = (evt.originalEvent || evt).touches[0].screenY;
                    var xPosition = (evt.originalEvent || evt).touches[0].screenX;
    
                    // If we scrolled, prevent long presses
                    if (touchStartY !== undefined && touchStartX !== undefined &&
                        (Math.abs(yPosition - touchStartY) > MAX_DELTA) || Math.abs(xPosition - touchStartX) > MAX_DELTA) {
                        $timeout.cancel(timer);
                    }
    
                }
            }
        };
    }]);