Here is my 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>
And there the ts file:
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();
}
}
Do you see something strange? It shouldn’t be a memory problem (or is so it is a ionic problem) because i have a virtual list of only 50-100 items. And if it is a memory problem how can I detect it? Also you can test the app in ionic view but it is really slow: C676D0D8