Loading map into ngSwitch extension area using ElementRef in Ionic
I am trying to access the ngSwitchCase view using @ViewChild and ElementRef to load the google map in my Ionic 3 app. I understand that ngSwitch creates its own scope, but it is not available anyway, so I can load the map from google in # map id = "map" div in mapView ngSwitchCase?
page.ts
//the import
import { ElementRef, ViewChild } from '@angular/core';
@Component({
selector: 'page-views',
templateUrl: 'views.html'
})
export class ViewsPage {
//the attribute in the export class
@ViewChild('map') mapElement : ElementRef;
views: string = "listView";
constructor(public navCtrl: NavController) {}
//the functions
ionViewDidLoad(){
this.loadMap();
}
loadMap(){
this.geolocation.getCurrentPosition().then((position) => {
let latLng = new google.maps.LatLng(position.coords.latitude, position.coords.longitude);
// initializing map attributes
let mapOptions = {
center: latLng,
zoom: 15,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
this.map = new google.maps.Map(this.mapElement.nativeElement, mapOptions);
});
}
}
page.html
<ion-toolbar>
<ion-segment [(ngModel)]="views">
<ion-segment-button value="mapView">
Map
</ion-segment-button>
<ion-segment-button value="listView">
List
</ion-segment-button>
</ion-segment>
</ion-toolbar>
<ion-content padding>
<div [ngSwitch]="views">
<ion-list *ngSwitchCase="'mapView'">
<ion-item>
<div #map id="map"></div>
</ion-item>
</ion-list>
<ion-list *ngSwitchCase="'listView'">
//other stuff
</ion-list>
</div>
</ion-content>
source to share
ngSwitch creates and destroys the corresponding DOM element dynamically. Since you are starting the default view, initialized to view the list with
views: string = "listView";
an ionic list that
<ion-list *ngSwitchCase="'mapView'">
does not exist in the DOM. Hence the div with the display being a child of the ionic list does not exist. Hence mapElement : ElementRef
it is null. Perhaps if you start by displaying a default segment with a map like
views: string = "mapView";
your code can run and create a map in one go. Just try it. I like. Note that when switching segments, the map is destroyed and may not be created again, since yours loadMap()
only works once.
At this point, you have two options.
-
Instead of ngSwitch (which creates / destroys items), use show / hide Map and List.
page.scss
.hide { display: none !important; }
page.html
<ion-content padding> <div #map id="map" [ngClass]="{ 'hide': views != 'mapView' }"></div> <div [ngClass]="{ 'hide': views != 'listView' }"> <ion-list > //other stuff </ion-list> </div> </ion-content>
-
You have a tab with a Map tab and a List tab.
page.ts
import { ElementRef, ViewChild } from '@angular/core'; import { ListPage } from '../list/list'; import { MapPage } from '../map/map'; @Component({ selector: 'page-views', templateUrl: 'views.html' }) export class ViewsPage { views: string = "listView"; tab1Root = MapPage; tab2Root = ListPage; constructor(public navCtrl: NavController) {} }
page.html
<ion-content> <ion-tabs> <ion-tab [root]="tab1Root" tabTitle="Map" tabIcon="map"></ion-tab> <ion-tab [root]="tab2Root" tabTitle="List" tabIcon="list"></ion-tab> </ion-tabs> </ion-content>
map.ts
. . export class MapPage { @ViewChild('map') mapElement : ElementRef; constructor(){} ionViewDidLoad(){ this.loadMap(); } loadMap(){ //stuff here } }
Also, I noticed that you are creating a list of cards with
<ion-list *ngSwitchCase="'mapView'">
<ion-item>
<div #map id="map"></div>
</ion-item>
</ion-list>
Don't you just need one card? Shouldn't it be
<div [ngSwitch]="views">
<div #map id="map" *ngSwitchCase="'mapView'"></div>
<ion-list *ngSwitchCase="'listView'">
.
.
source to share