I have this provider:
import {Injectable} from '#angular/core';
import {CommonService} from "./common-service";
import { Storage } from '#ionic/storage';
import 'rxjs/add/operator/filter';
declare var google;
#Injectable()
export class Maps{
load_map(selector:any,zoom:number,center_coords:any = {lat: this.lat ,lng: this.lng}){
this.lat = center_coords.lat;
this.lng = center_coords.lng;
return new Promise((resolve,reject) => {
let latLng = new google.maps.LatLng(center_coords.lat, center_coords.lng);
let mapOptions = {zoom: zoom};
this.map = new google.maps.Map(selector, mapOptions);
if(this.map){
return resolve(this.map);
}else{
return reject({error:"can not load maps"});
}
})
}
set_center(lat :number = this.lat,lng :number = this.lng){
let latLng = new google.maps.LatLng(lat, lng);
this.map.setCenter(latLng);
}
}
i use a factory in my app module:
{
provide: 'Maps',
useFactory: () =>
new Maps(),
deps: []
},
In my page i import the service:
#Component({
selector: 'page-report',
templateUrl: 'report.html'
})
export class ReportPage{
public map:any;
#ViewChild('reportmap') mapElement :ElementRef;
construct(#Inject('Maps') mapsfactory){
this.map = mapsfactory;//this is a new instance always
this.map.load_map(mapElement,16,{lat:123,lng:123});
this.map.set_center(234,234);
}
}
other page:
#Component({
selector: 'other-page',
templateUrl: 'other-page.html'
})
export class OtherPage{
public map:any;
#ViewChild('map') mapElement :ElementRef;//diferent input
construct(#Inject('Maps') mapsfactory){
this.map = mapsfactory;
this.map.load_map(mapElement,16,{lat:123,lng:123});
}
}
In app init works fine, but if change the center in second instance (OtherPage) using a click or other event to change center affects to ReportPage map, i try reset center to original position but not render correctly, use the factory to create two diferent instances of maps but doesn't work, this problem only appear when change center of map. elementRef are diferents id and input attribute, all is diferent between the instances! on browser it´s ok, this problem only appear in android device, i newbie using angular 2 and ionic 2, i think android optimizes maps by creating a single instance, Any idea or similar problem to resolve together?
I think in a bad solution but I could not do it; reload tab 0 (reportpage) after finish work in tab 1 (otherPage) and reload after click on tab 0.
Related
All the below testing and coding is done for Android phone.
I have created a new tabs project using ionic tabs. And I have 4 tabs at the bottom right now. Now the problem is I clicked on another tab no the view and then try to use the default SwipeToGoBack gesture in the phone and that does nothing.
If I go into any other page then the back gesture works fine, but when I am in the 4 pages of the tabs, it does not work.
I tried below options:
<ion-router-outlet id="main" [swipeGesture]="true"></ion-router-outlet>
IonicModule.forRoot({
swipeBackEnabled: true
}
But those did not help. I can even close the side menu bar opened by swipe back. But can not go to the previous tab by swiping back on phone. Even not able to close the app.
If the application is opened and no other tabs were clicked and I do the swipe back gesture then the app closes, but as soon as I click on other tabs then I can not even come out of the application.
I also tried adding back button listeners from the platform but that also did not help. I added below code part in the tabs.page.ts:
this.platform.backButton.subscribe(() => {
navigator.app.exitApp();
});
Any help on how to go back to the previous tab on swipe back gesture on phone and finally close the app if no previous tab history?
Links already tried:
https://github.com/ionic-team/ionic/issues/12927
Handling hardware back button in Ionic3 Vs Ionic4
Swipe through segment tabs - Ionic 3
export class TabsPage {
navigationProccess:Array<any> = [];
lastTabName:string = "";
currentBack:string = "";
constructor(private platform: Platform,private router:Router,private navctrl:NavController) {
this.router.events.subscribe((event:RouterEvent)=>{
if(event.url !== undefined){
if(this.lastTabName !== event.url && event.url !== this.currentBack){
// we put last tab name not equal event.url so the event don't go twice through array
// we put event.url not equal current back that is since when navcontroll in back button go back its considered a router event and we don't need it to be inserted again
this.pushTabHistory(event.url);
}
this.lastTabName = event.url;
}
});
this.platform.backButton.subscribeWithPriority(99999999,async()=>{
let pushHistoryCount = this.navigationProccess.length;
if(this.router.url.includes('tabs') == true && pushHistoryCount > 1){
let url = this.navigationProccess[pushHistoryCount-2].url;
this.navigationProccess.splice(pushHistoryCount-1, 1);
this.currentBack = url;
//currentBack should be assigned before navgiate back
this.navctrl.navigateBack(url);
}
})
}
pushTabHistory(tabName:string){
let navHistory = {
url:tabName
};
this.navigationProccess.push(navHistory)
}
}
Mate i've edited my answer and you where right.
Tabs don't have routeroutlet.cangoBack() since tabs and tabs/tab1ortab2ortab3 are considered one level and can't go backward.
Here i created the way to make navigation history inside array and go back and forward from this array but subscribe back is from tabs page and i make it like that since you could making it just for testing.
But As an advanced way here we go ->
1) Create A service tabnav:
import { Injectable } from '#angular/core';
#Injectable({
providedIn: 'root'
})
export class TabnavService {
public navigationProccess:Array<any> = [];
public lastTabName:string = "";
public currentBack:string = "";
constructor() { }
pushTabHistory(tabName:string){
let navHistory = {
url:tabName
};
this.navigationProccess.push(navHistory)
}
}
2)Inside Your TabsPage:
import { TabnavService } from './../services/tabnav.service';
import { Router, RouterEvent } from '#angular/router';
import { Component } from '#angular/core';
import { NavController, Platform } from '#ionic/angular';
#Component({
selector: 'app-tabs',
templateUrl: 'tabs.page.html',
styleUrls: ['tabs.page.scss']
})
export class TabsPage {
constructor(private platform: Platform,
private router:Router,
private tabNavService:TabnavService) {
if(this.platform.is('android')){
this.router.events.subscribe((event:RouterEvent)=>{
if(event.url !== undefined){
if(this.tabNavService.lastTabName !== event.url && event.url !== this.tabNavService.currentBack){
// we put last tab name not equal event.url so the event don't go twice through array
// we put event.url not equal current back that is since when navcontroll in back button go back its considered a router event and we don't need it to be inserted again
this.tabNavService.pushTabHistory(event.url);
}
this.tabNavService.lastTabName = event.url;
}
});
}
}
}
3) In app.component.ts :
import { TabnavService } from './services/tabnav.service';
import { Component, ViewChild } from '#angular/core';
import { Platform, IonRouterOutlet, NavController } from '#ionic/angular';
import { SplashScreen } from '#ionic-native/splash-screen/ngx';
import { StatusBar } from '#ionic-native/status-bar/ngx';
import { Router } from '#angular/router';
#Component({
selector: 'app-root',
templateUrl: 'app.component.html',
styleUrls: ['app.component.scss']
})
export class AppComponent {
#ViewChild(IonRouterOutlet,{static:false}) routerOutlet:IonRouterOutlet;
constructor(
private platform: Platform,
private splashScreen: SplashScreen,
private statusBar: StatusBar,
private router:Router,
private navctrl:NavController,
private tabNavService:TabnavService
) {
this.initializeApp();
}
initializeApp() {
this.platform.ready().then(() => {
this.statusBar.styleDefault();
this.splashScreen.hide();
this.platform.backButton.subscribeWithPriority(99999999,async()=>{
let pushHistoryCount = this.tabNavService.navigationProccess.length;
if(this.router.url.includes('tabs') == true && pushHistoryCount > 1){
let url = this.tabNavService.navigationProccess[pushHistoryCount-2].url;
this.tabNavService.navigationProccess.splice(pushHistoryCount-1, 1);
this.tabNavService.currentBack = url;
//currentBack should be assigned before navgiate back
this.navctrl.navigateBack(url);
}else if(this.router.url.includes('tabs') == true && pushHistoryCount <2){
// here is the array less than 2 which is one (you could make it ==0 but i make it if app glitches or something)
//so if app is on main start point it exit on back pressed
navigator['app'].exitApp();
}
});
});
}
}
And Thats All ^^ . Any Help Just comment here again ^^.
I'm trying to get coordinates of my device location using the cordova geolocation plugin.
When running the app on android (10), I get prompted for location permissions which I set to always allow and after that my getLocation function gets executed but I don't get any of the additional feedback which I programmed in to suggest that it has actually received coordinates.
For the moment don't focus on the loadMap component, my focus currently is to retrieve coordinates,
I already did the import in app.module.ts
This is my home.page.ts
(For debug purposes I chained together the loadMap function and getLocation function to make sure the getLocation function gets executed (which it does judging by the begin location flow message I receive)
import { Component, ViewChild } from '#angular/core';
import { Geolocation} from '#ionic-native/geolocation/ngx';
// Import classes from maps module
import {
GoogleMaps,
GoogleMap,
GoogleMapsEvent,
LatLng,
MarkerOptions,
Marker
} from '#ionic-native/google-maps';
import { Platform, NavController } from '#ionic/angular';
#Component({
selector: 'app-home',
templateUrl: 'home.page.html',
styleUrls: ['home.page.scss'],
})
export class HomePage {
lat;
lng;
constructor( public platform: Platform, public nav: NavController, private geolocation: Geolocation ) {
}
ngAfterViewInit() {
this.platform.ready().then( () => {
this.loadMap();
});
this.getLocation();
}
loadMap() {
console.log('map render start');
let map = GoogleMaps.create( 'map' );
map.one( GoogleMapsEvent.MAP_READY ).then( ( data: any ) => {
let coordinates: LatLng = new LatLng( 50.7783, 119.4179 );
let position = {
target: coordinates,
zoom: 14
};
map.animateCamera( position );
let markerOptions: MarkerOptions = {
position: coordinates,
icon: "assets/images/marker.png",
title: 'Hello California'
};
const marker = map.addMarker( markerOptions )
.then( ( marker: Marker ) => {
marker.showInfoWindow();
});
});
this.getLocation();
}
getLocation() {
console.log('begin location flow');
this.geolocation.getCurrentPosition().then((resp) => {
// resp.coords.latitude
// resp.coords.longitude
this.lat = resp.coords.latitude;
this.lng = resp.coords.longitude;
alert('lat' + this.lat + 'lon' + this.lng);
console.log('location succes');
}).catch((error) => {
console.log('Error getting location', error);
});
}
}
you need to move the method your calling that makes use of the native plugin into the platform ready promise call back. Native plugins cannot be used until this fires.
this.platform.ready().then(() => {
this.getLocation();
})
Based on your code above, you're calling this.getLocation() twice, as you pointed out, however, the first/initial this.getLocation() call gets run probably before this.platform.ready() (see ngAfterViewInit() routine).
Could this cause a conflict?
I am a beginner in Ionic and I am developing an app which requires a user to sign in before he places an order.
Right now, if the user tries to place an order and he is not signed in, I need a logic where I can redirect him to the login page and on success, I can redirect him back to the order page. This would have been possible in android using start activity for the result. But how can I achieve this in Ionic?
I have a solution of opening the login page using modal and dismissing it on success but I do not want to implement that solution as of now.
Here is an example whcih open modal via login. Path and IonicPage should be adjusted before using the below code. Maybe you can get a point from the code.
home.ts
import { Component } from '#angular/core';
import { AuthProvider } from '../../providers/auth/auth.provider'
#Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage {
constructor(public authService:AuthProvider) {
}
goToOrder(){
this.authService.openModalViaLogin('OrderPage', {}, ()=>{})
}
}
login.ts
import { Component } from '#angular/core';
import { IonicPage, ViewController } from 'ionic-angular';
import { AuthProvider } from '../../providers/auth/auth.provider';
#IonicPage()
#Component({
selector: 'page-login',
templateUrl: 'login.html',
})
export class LoginPage {
constructor(public authService:AuthProvider, public viewCtrl:ViewController) {
}
login(){
this.authService.isAuthenticated = true;
this.viewCtrl.dismiss()
}
close(){
this.viewCtrl.dismiss()
}
}
auth.provider.ts
import { Injectable } from '#angular/core';
import { ModalController } from 'ionic-angular';
#Injectable()
export class AuthProvider {
public isAuthenticated:boolean = false;
constructor(public modalCtrl:ModalController) {
console.log('Hello AuthProvider Provider');
}
public openModalViaLogin(modalPage:string, params:any, callbackOnDidDismissed:Function){
if(this.isAuthenticated){
let modal = this.modalCtrl.create(modalPage,params)
modal.onDidDismiss(()=>{
callbackOnDidDismissed()
})
modal.present()
}else{
let loginModal = this.modalCtrl.create('LoginPage')
loginModal.onDidDismiss(()=>{
if(this.isAuthenticated){
let modal = this.modalCtrl.create(modalPage,params)
modal.onDidDismiss(()=>{
callbackOnDidDismissed()
})
modal.present()
}else{
console.log("failed to authenticate")
}
})
loginModal.present()
}
}
}
p.s. I think there is a more flexible way to achieve it by nav but that can be quite confusing with this short anwser.
I have found on android that using geolocation from Google Maps JavaScript API and from the Ionic Framework has caused issues of being very slow or not working at all. I then found a second geolocation module for Ionic called LocationService, from this documentation: https://github.com/ionic-team/ionic-native-google-maps/blob/master/documents/locationservice/README.md. The issue that I am having is although this Location module is working for Android, it is not working on ios or by serving the app on localhost. Below is the error that I am getting and my code that sets the map's center. I am editing this.
map.html:
<ion-header>
<ion-navbar>
<ion-title>
Map
</ion-title>
</ion-navbar>
</ion-header>
<ion-content>
<div id='map'></div>
</ion-content>
map.ts:
import { Component, ViewChild, ElementRef } from '#angular/core';
import { NavController, Platform, Navbar } from 'ionic-angular';
import { Geolocation } from '#ionic-native/geolocation';
import {
LocationService,
GoogleMap,
GoogleMapOptions,
MyLocation,
GoogleMaps
} from '#ionic-native/google-maps';
declare var google: any;
#Component({
selector: 'page-map',
templateUrl: 'map.html',
})
export class OfficeLocatorPage {
#ViewChild(Navbar) navBar: Navbar;
map: any;
mapOptions:any;
trafficEnabled = false;
transitEnabled = false;
bicycleEnabled = false;
markers = [];
places = [];
trafficLayer = new google.maps.TrafficLayer();
transitLayer = new google.maps.TransitLayer();
bicycleLayer = new google.maps.BicyclingLayer();
myLocation: any;
infoWindow: any;
isInfoWindowShown: boolean = false;
constructor(private navCtrl: NavController, private platform: Platform, private geolocation: Geolocation) {
}
ionViewDidLoad() {
this.navBar.backButtonClick = (e:UIEvent)=>{
this.navCtrl.pop({animate: true, animation: "transition", direction: "left", duration: 300});
};
}
ionViewDidEnter() {
this.platform.ready().then(() => {
this.places = [];
this.initMap(this);
});
}
initMap(scopeObj) {
LocationService.getMyLocation({enableHighAccuracy: true}).then((location: MyLocation) => {
this.setLocation(location.latLng);
}).catch((error: any) => {
// Can not get location, permission refused, and so on...
console.log(error);
});
}
setLocation(location) {
this.map = new google.maps.Map(document.getElementById('map'), {
center: location,
zoom: 10,
disableDefaultUI: true
});
let image = {
url: "assets/icon/blue_dot.png", // url
scaledSize: new google.maps.Size(25, 33), // scaled size
origin: new google.maps.Point(0,0), // origin
anchor: new google.maps.Point(0, 0) // ancho
};
let marker = new google.maps.Marker({
position: location,
map: this.map,
icon: image
});
this.myLocation = new google.maps.LatLng(location.lat, location.lng);
}
Error log:
Error: Uncaught (in promise): TypeError: Cannot read property 'LocationService' of null
TypeError: Cannot read property 'LocationService' of null
at http://localhost:8100/build/vendor.js:78338:35
at new t (http://localhost:8100/build/polyfills.js:3:21506)
at Function.LocationService.getMyLocation
The error seems to only show when serving the app in a web browser, Xcode just needed to be cleaned and rebuilt, so the map shows up and works now. I don't believe that it will work on the browser when running the command "ionic serve", because LocationService is an ionic native module and can't be used unless the app is installed on Android or iOS.
I am using Ionic together with the native Geolocation plugin to retrieve user position and sort a list of position by closest to the user.
The Geolocation plugin works perfectly using ionic serve or ionic lab as well as iOS devices but it does not work on Android devices (nor simulator).
What other solution can I use to retrieve longitude and latitude of the user?
I'll attach the class where I use the Geolocation plugin here.
The Location class I access has a public static variable where I store the userLocation since will be modified in more classes.
this.Location.load just uses the user position to call a method in Location class to sort the list of places.
import { Component } from '#angular/core';
import { ModalController, NavController, NavParams } from 'ionic-angular';
import { SharePopup } from '../share-popup/share-popup';
import { InAppBrowser } from 'ionic-native';
import { CamhsPage } from '../camhs-page/camhs-page';
import { Locations } from '../../providers/locations';
import { Platform } from 'ionic-angular';
import { Geolocation } from 'ionic-native';
#Component({
selector: 'contact',
templateUrl: 'contact.html'
})
export class Contact {
userPosition = [0, 0];
constructor(public navCtrl: NavController, public navParams: NavParams,
public modalCtrl: ModalController, public locations: Locations,public platform: Platform) {
}
openCamhsPage(){
this.platform.ready().then(() => {
let options = {
timeout: 10000,
enableHighAccuracy: true
};
Geolocation.getCurrentPosition(options).then((data) => {
Locations.userPosition[0] = Math.round(data.coords.latitude * 100)/100;
Locations.userPosition[1] = Math.round(data.coords.longitude * 100)/100;
// console.log("CONTACT "+Locations.userPosition);
});
});
this.locations.load();
this.navCtrl.push(CamhsPage);
console.log("CONTACT "+Locations.userPosition);
}
//Open WebPage
openPage(url) {
new InAppBrowser(url, '_system');
}
}
Prerequisite : Check whether you have switch ON your GPS service in Android.
Also it is good to have Success and Error Callbacks to identify the actual Error. Something like below :
..........
// Success callback for get geo coordinates
var onSuccess = function (data) {
Locations.userPosition[0] = Math.round(data.coords.latitude * 100)/100;
Locations.userPosition[1] = Math.round(data.coords.longitude * 100)/100;
}
var onError = function (data) {
console.log("Not Able to get Geolocation");
}
openCamhsPage(){
this.platform.ready().then(() => {
Geolocation.getCurrentPosition(onSuccess, onError, { enableHighAccuracy: true });
this.locations.load();
this.navCtrl.push(CamhsPage);
console.log("CONTACT "+Locations.userPosition);
}
.......
.......