question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Click delay (2s) on device but not in browser.

See original GitHub issue

Ionic version: [X] 2.2.0

I’m submitting a … [X] bug report

Current behavior: I’m facing a click delay problem while test my app on real device (IOS/Android). While testing on browser, clicks are very fast responsive but when I test the app on Iphone 5C or Android devices (or emulator) there is to much delay (like 2s).

You can see the difference: ON BROWSER ON IPHONE 5C

Expected behavior: No click delays on device.

Steps to reproduce: Using WKWebView with virtual list. (but without WKWebView it’s the same)

Related code: HTML:

<ion-header>
  <ion-navbar>
  <ion-buttons  end >
      <button [hidden]="!showScrollTop" ion-button style="font-size:24px;" (click)="scrollToTop()">
       <ion-icon name="arrow-up"></ion-icon>
      </button>
    </ion-buttons>
    <ion-title>
      <span>Garages</span>
    </ion-title>

  </ion-navbar>
</ion-header>





<ion-content class="feed-content">

   <ion-refresher (ionRefresh)="doRefresh($event)">
    <ion-refresher-content></ion-refresher-content>
  </ion-refresher>


    <ion-toolbar class="search-toolbar border-bottom">
    <ion-buttons start>
      <button ion-button icon-only (click)="geolocateMe()" class="geolocation-button" >
        <ion-icon name="locate"></ion-icon>
      </button>
    </ion-buttons>
    <span class="actual-pos" placeholder="" >Position actuelle: {{adresse_actuelle}}</span>
  </ion-toolbar>

  <form [formGroup]="rangeForm">
    <ion-list class="range-list">
      <ion-item class="range-item single-range">
        <ion-label>
          <h2 class="range-label">Distance maximale:</h2>
          <h3 class="range-value">{{rangeForm.controls.single.value}}km</h3>
        </ion-label>
        <ion-range formControlName="single" (ionChange)="rangeChange($event)" min="1" max="50" step="1" snaps="true" pin="false" ></ion-range>

      </ion-item>
    </ion-list>
  </form>


  <ion-col [hidden]="!rangeUpdated" no-padding width-100 class="refresh-arrow-col">
    <div  > 
      <p class="refresh-text">Tirez pour rafraichir les résultats</p>
      <ion-icon class="refresh-arrow" name="arrow-down"></ion-icon>
    </div>
  </ion-col>

  <ion-col no-padding width-100 class="refresh-arrow-col">
      <p class="refresh-text" style="padding-bottom:15px;">Garages à proximité: <strong>{{feed?.posts?.length}}</strong></p>
  </ion-col>



 <ion-list [virtualScroll]="feed.posts" approxItemHeight="100px"  no-lines>
  <div class="feed-item" *virtualItem="let post" style="width: 100%">
    <ion-card [class.premium]="post.premium==1">

      
      <ion-row tappable class="user-main-data-row" (click)="goToGarage(post.garage.id)" >
         <div *ngIf="post.premium==1">
           <span class="premium-text">SPONSORISÉ</span>
      </div> 
        <ion-col no-padding width-33>

          <preload-image class="user-image" [ratio]="{w:1, h:1}" src="http://garageadvisor.pre-production.ovh/upload/{{post.garage.logo}}" alt=""  ></preload-image>
        </ion-col>
        <ion-col class="center" no-padding width-67 style="padding-left:5px;">
          <p class="item-title">{{post.garage.nom}}</p>

 
              <p class="avis-list">Note: <span class="note">{{post.garage.moyenneAvis}}/5</span> ({{post.garage.nbAvis}} Avis) </p>

        </ion-col>
      </ion-row>

      <ion-card-content tappable (click)="goToGarage(post.garage.id)">
   
                 <ion-list class="details-list" no-lines>
                  <ion-item class="place-location">
                    <ion-avatar item-left>
                      <ion-icon name="pin"></ion-icon>
                    </ion-avatar>
                    <div *ngIf="post.distance<1">
                      <span class="location-text">{{post.garage.adresse}} (à {{post.distance*1000 | num }} m)</span>
                    </div> 
                    <div *ngIf="post.distance>1">
                      <span class="location-text">{{post.garage.adresse}} (à {{post.distance | num }} km)</span>
                    </div> 
                  </ion-item>
                </ion-list>
      </ion-card-content>
      <ion-row no-padding class="actions-row">
        <ion-col no-padding width-50 text-left>
          <button tappable class="action-button" ion-button clear small icon-left (click)="goToGarage(post.garage.id)">
            <ion-icon name='pricetags'></ion-icon>
            {{post.nombrePromotion}} Promotion(s)
          </button>
        </ion-col>
        <ion-col  no-padding width-45 text-right >
          <button  class="action-button" ion-button clear small icon-left (click)="navigate(post.garage.adresse)">
            <ion-icon name='navigate'></ion-icon>
            Itinéraire
          </button>
        </ion-col>

      </ion-row>
    </ion-card>
    <div style="height:12px"></div>
  </div>
  </ion-list>
</ion-content>

component.ts:

import { Component, ViewChild, ChangeDetectorRef } from '@angular/core';
import { Content } from 'ionic-angular';
import { Geolocation } from '@ionic-native/geolocation';
import { NavController, NavParams, LoadingController, AlertController, ToastController } from 'ionic-angular';
import { LaunchNavigator, LaunchNavigatorOptions } from '@ionic-native/launch-navigator';
import { FormGroup, FormControl } from '@angular/forms';
import { ProfilePage } from '../profile/profile';
import { ContactCardPage } from '../contact-card/contact-card';
import 'rxjs/Rx';
import { FeedPostModel } from './feed.model';
import { FeedModel } from './feed.model';
import { FeedService } from './feed.service';
import { SocialSharing} from '@ionic-native/social-sharing';
import { WalkthroughPage } from '../walkthrough/walkthrough';
import {App} from 'ionic-angular';
import { NativeStorage } from '@ionic-native/native-storage';


import { LoginService } from '../login/login.service';


@Component({
  selector: 'feed-page',
  templateUrl: 'feed.html'
})
export class FeedPage {
  feed: FeedModel = new FeedModel();
  rangeForm: any;
  loading: any;
  page: number;
  next: boolean;
  rangeUpdated:boolean;
  latitude:any;
  longitude:any;
  adresse_actuelle:string;
  range_distance:any;
  showScrollTop:boolean;

  constructor(
    public app: App,
    public nav: NavController,
    public feedService: FeedService,
    public navParams: NavParams,
    public loadingCtrl: LoadingController,
    public alertCtrl: AlertController,
    private launchNavigator: LaunchNavigator,
    public loginService: LoginService,
    public toastCtrl: ToastController,
    private geolocation: Geolocation,
    private socialSharing: SocialSharing,
    public nativeStorage: NativeStorage,
    private changeDetectorRef: ChangeDetectorRef

  ) {

    this.loading = this.loadingCtrl.create();

    this.page=0;

    this.next=false;

    this.rangeUpdated=false;

    if (localStorage.getItem("range_distance"))this.range_distance=localStorage.getItem("range_distance");
    else this.range_distance=25;

    this.rangeForm = new FormGroup({
      single: new FormControl(this.range_distance)
    });

    this.latitude=0; 
    this.longitude=0;
    this.adresse_actuelle=localStorage.getItem("adresse-actuelle");
    this.showScrollTop=false;

    
  }


  ionViewDidLoad() {

    let loading = this.loadingCtrl.create({
      content: 'Mise à jour de votre position'
    });
    loading.present();
    let posOptions = {enableHighAccuracy: true};
    this.geolocation.getCurrentPosition(posOptions).then((position) => {
          localStorage.setItem("latitude", String(position.coords.latitude));     // Ajoute la latitude
          localStorage.setItem("longitude", String(position.coords.longitude));   // Ajoute la longitude
          loading.dismiss().catch(() => {});
          let loading2 = this.loadingCtrl.create();
          loading2.present();
          this.loginService.
          getAdresse()            
          .then(data => {
                  localStorage.setItem("adresse-actuelle", data[0].long_name+" "+data[1].long_name+", "+data[2].long_name);
                  this.adresse_actuelle=data[0].long_name+" "+data[1].long_name+", "+data[2].long_name;
                  this.feedService
                  .getGarages(0, this.rangeForm.controls.single.value, 1000)
                  .then(data => {
                        this.feed.posts = data.Content as FeedPostModel[];
                        this.next = data.Next;
                        loading2.dismiss().catch(() => {});
                  }).catch(error => { 
                    loading2.dismiss().catch(() => {});
                    this.errorAlert(error);
                  });
          }).catch((error) => {
          loading2.dismiss().catch(() => {});
          this.errorAlert("GoogleMap");
          });
          
          loading.dismiss().catch(() => {});

    }).catch((error) => {
      loading.dismiss().catch(() => {});
      this.errorAlert("GPS");
    });



  }

  @ViewChild(Content) content: Content;

  scrollToTop() {
    this.content.scrollToTop(2000);
    this.showScrollTop=false;
  }

  ngAfterViewInit() {
    this.content.ionScrollEnd.subscribe((data)=>{
      if (data.scrollTop > 1000) {
        this.showScrollTop=true;
      } else {
        this.showScrollTop=false;
      }
      this.changeDetectorRef.detectChanges();
    });
  }

  ionViewDidEnter () {
      if (this.adresse_actuelle!=localStorage.getItem("adresse-actuelle"))this.rangeUpdated=true;
      this.adresse_actuelle=localStorage.getItem("adresse-actuelle");
  }

   doInfinite(infiniteScroll) {
      this.page++;
      this.feedService
        .getGarages(this.page, this.rangeForm.controls.single.value, 10)
        .then(data => {
          this.feed.posts = this.feed.posts.concat(data.Content as FeedPostModel[]);
          this.next = data.Next;
          infiniteScroll.complete();
        }).catch(error => { 
        this.loading.dismiss().catch(() => {});
        this.errorAlert(error);
      });
  }

  goToProfile(event, item) {
    this.nav.push(ProfilePage, {
      user: item
    });
  }

  getRandomInt(min, max) {
    return Math.floor(Math.random() * (max - min + 1)) + min;
  }

  sharePost(post) {
   //this code is to use the social sharing plugin
   // message, subject, file, url
   this.socialSharing.share(post.description, post.title, post.image)
   .then(() => {
 
   })
   .catch(() => {
  
   });
 }


  rangeChange(range: Range) {
    this.rangeUpdated=true;  
    localStorage.setItem("range_distance", this.rangeForm.controls.single.value);

  }

  goToGarage(id_garage: any) {
      this.nav.push(ContactCardPage, { id_garage: id_garage });
  }

  doRefresh(refresher) {
    this.page=0;
    this.feedService
    .getGarages(0, this.rangeForm.controls.single.value, 1000)
    .then(data => {
      this.feed.posts = data.Content as FeedPostModel[];
      this.next = data.Next;
      this.rangeUpdated=false;
      refresher.complete();
    }).catch(error => { 
      this.loading.dismiss().catch(() => {});
      this.errorAlert(error);
    });
  }


  navigate(adresse){
    let options: LaunchNavigatorOptions = {
      //start: [parseFloat(localStorage.getItem("latitude")),parseFloat(localStorage.getItem("longitude"))],
      appSelectionDialogHeader: "Veuillez choisir l'application GPS",
      appSelectionCancelButton: "Annuler"
    };

  this.launchNavigator.navigate(adresse, options)
    .then(
      success => console.log('Launched navigator'),
      error => console.log('Error launching navigator', error)
    );


  }

  geolocateMe(){
    let loading = this.loadingCtrl.create();
    loading.present();
    let posOptions = {enableHighAccuracy: true};
    this.geolocation.getCurrentPosition(posOptions).then((position) => {
    localStorage.setItem("latitude", String(position.coords.latitude));     // Ajoute la latitude
    localStorage.setItem("longitude", String(position.coords.longitude));   // Ajoute la longitude
   
    this.loginService.
    getAdresse()            
    .then(data => {
      localStorage.setItem("adresse-actuelle", data[0].long_name+" "+data[1].long_name+", "+data[2].long_name);
      this.adresse_actuelle=data[0].long_name+" "+data[1].long_name+", "+data[2].long_name;
    }).catch((error) => {
    loading.dismiss().catch(() => {});
    });
    this.rangeUpdated=true;
    let toast = this.toastCtrl.create({
    message: "Votre position a bien été mise à jour.",
    duration: 3000,
    position: 'bottom'
    });
    toast.present();
    loading.dismiss().catch(() => {});

    }).catch((error) => {
      loading.dismiss().catch(() => {});
      this.errorAlert("GPS");
    });
  }



  errorAlert(error) {
    let message:string;
    if (error=="GPS"){ 
      message="Veuillez autoriser GarageAdvisor à accéder au service de localisation de votre téléphone et réessayez.";
    } else if (error=="GoogleMap") { 
      message="GoogleMap n'est pas accèssible. Veuillez réessayer ultérieurement."; 
    } else {
      if (error.status==400){
          message=error.json().Error;
      } else if (error.status==401){
          message="Votre session a expiré. Veuillez vous reconnecter."
      } else if (error.status==403){
          if (error.json().Error=="No_Enabled"){
            message="Votre compte a été suspendu. Veuillez contacter l'administrateur."
          } else  {
            message="Vous n'avez pas les droits d'accèder à cette page."
          }
      } else if (error.status==404){
          if (error.json().Error=="Not_Found_Garage"){
            message="Ce garage n'existe pas ou a été supprimé.";
          } else if (error.json().Error=="Not_Found_Promotion"){
            message="Cette promotion n'existe pas ou a été supprimée.";
          } else if (error.json().Error=="Not_Found_Member"){
            message="Votre compte n'existe pas ou a été supprimé.";
          } else if (error.json().Error=="Not_Found_Vente"){
            message="Cette vente n'existe pas ou a été supprimée.";
          } else if (error.json().Error=="Not_Found_Avis"){
            message="Cet avis n'existe pas ou a été supprimé.";
          } else message="Page introuvable.";
      } else message="Une erreur interne est survenue. Veuillez réessayer ultérierement."
    }

    let alert = this.alertCtrl.create({
      title: 'Erreur',
      subTitle: message,
      buttons: [
      {
        text: 'Ok',
        role: 'cancel',
        handler: () => {
          if ((error.status==401) || (error.status==500) || ((error.status==403) && (error.json().Error=="No_Enabled"))){
            localStorage.setItem("token","");
            localStorage.setItem("email","");
            localStorage.setItem("id","");
            this.nativeStorage.clear();
            this.app.getRootNav().setRoot(WalkthroughPage);
          }
          if ((error.status==404) || ((error.status==403) && (error.json().Error!="No_Enabled")) ){
            this.nav.pop();
          }
        }
      }
    ]
    });
    alert.present();
  }



}

Other information: The problem persist on both platforms (iOS & Android). There is no exceptions thrown in console. Migrating to 3.2.0 didn’t solve the problem. I tried to only display a button in virtual scroll (without images etc), didn’t solve the problem. Uninstalling WKWebView didn’t solve the problem.

Ionic info:

Cordova CLI: 6.5.0 
Ionic Framework Version: 2.2.0
Ionic CLI Version: 2.2.1
Ionic App Lib Version: 2.2.0
Ionic App Scripts Version: 1.1.4
ios-deploy version: Not installed
ios-sim version: 5.0.6 
OS: macOS Sierra
Node Version: v7.7.3
Xcode version: Xcode 8.3.2 Build version 8E2002

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Reactions:2
  • Comments:11 (3 by maintainers)

github_iconTop GitHub Comments

2reactions
chandanchcommented, May 21, 2017

@evenmind The delay is expected for the components that are not clickable. In your code above, <ion-item> is not a clickable component hence the delay. Try doing it this way:

<ion-list>
    <button ion-item (click)="doOne()">Item1</button>
    <button ion-item (click)="doTwo()">Item2</button>
    <button ion-item (click)="doThree()">Item3</button>
</ion-list>

to avoid the delay. Refer to this click-delays for more information

1reaction
evenmindcommented, May 24, 2017

@manucorporat Any ideas for the workaround?

Read more comments on GitHub >

github_iconTop Results From Across the Web

Click delay Browser VS Device, how to improve?
I'm facing a click delay problem while test my app on real device (IOS/Android) with Ionic2. I have a VirtualList of 5 items...
Read more >
How to fix websites that delay for several seconds and then ...
Hi,. I use aol 9.7 software which has an adapter that connects the software to internet explorer for its browser.
Read more >
5 Ways to Prevent the 300ms Click Delay on Mobile Devices
5 Ways to Prevent the 300ms Click Delay on Mobile Devices · 1. Don't Fret About it · 2. Disable Zooming (Chrome and...
Read more >
Click delay Browser VS Device - Ionic Forum
Hi, i'm facing a click delay problem while test my app on real device ... While testing on browser, clicks are very fast...
Read more >
How to bind 'touchstart' and 'click' events but not respond to both
The touchstart event occurs when the user touches an element. But a click event is fired when the user clicks an element.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found