Search code examples
javascriptangularjsmobileangularjs-material

Click events stop working on firefox mobile after calling a time intensive function


All click events (ng-click functions as well as click functions bound with plain js via addEventListener) do not get triggered after a function gets called that needs some calculation (or rendering) time.

Things i noticed after the click events stop working:

  • javascript keeps running (i tested it with a simple setIntervall function which prints something to the console).
  • i debug the website remotely with Firefox WebIDE and there is no error or warning in the console.
  • the click events are still bound to the elements and triggering the click event via the console with getElementById("...").click() works.
  • everything works fine for firefox / chrome / ie on desktop version.
  • to make the click events work again i have to reload the page.
  • reducing the load or removing the , "ngMaterial", "ngMessages" dependencies will prevent the bug from happening
  • the console stops printing "clicked" as soon as the bug snaps in.

Here is a minimal example, you may have to change the load variable such that it takes at least 5 seconds to finish calculating. Just click the "calculate" headline to start the heavy load function. If it calculates long enough the "calculate" button stops working.

<html lang="en">

<head>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/angular_material/1.1.8/angular-material.min.css">
</head>

<body ng-app="BlankApp" ng-controller="heavywork" ng-cloak>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular.min.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular-animate.min.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular-aria.min.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular-messages.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.2/angular-route.min.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/angular_material/1.1.8/angular-material.min.js"></script>

    <script type="text/javascript">
        document.body.addEventListener("click", function () { console.log("clicked"); });
        document.body.addEventListener("touchend", function () { console.log("touchend"); });

        var app = angular.module('BlankApp', ["ngRoute", "ngMaterial", "ngMessages"]);
        app.controller("heavywork", function ($scope) {
            $scope.count = 0;
            $scope.calculate = function () {
                $scope.count += 1;
                //Edit load here such that it takes at least 5 seconds to finish
                var load = 1000000000;
                for (i = 0; i < load; i++) var x = Math.sqrt(10000);
            }
        })
    </script>

    {{count}}
    <h1 ng-click="calculate()">calculate</h1>
</body>

</html>

Solution

  • You will want to disable click hijacking if you run into problems like this.

    app.config(function($mdGestureProvider) {
      $mdGestureProvider.skipClickHijack();
    });
    

    Here's a fixed CodePen. It can be tested on mobile here.

    The documentation for this can be found here.