Ionic 3 Google Maps Integration - javascript

I am following this tutorial exactly: https://www.djamware.com/post/58f4da2080aca7414e78a638/step-by-step-tutorial-of-ionic-3-angular-4-and-google-maps-directions-service
But I cannot get it to work. I have the API key set up no problem, but for some reason I keep getting the error Error: Uncaught (in promise): ReferenceError: google is not defined
ReferenceError: google is not defined
I am running the app using ionic lab
For some reason it isn't working. Can someone help me find the problem? I have tried adding the cordova whitelist plugin, changing the https to http in the API key part, but still it isn't working.

Did you declare the variable at home.ts?
import { Component, ViewChild, ElementRef } from '#angular/core';
import { IonicPage } from 'ionic-angular';
import { NavController } from 'ionic-angular';
declare var google;
#IonicPage()
#Component({
selector: 'page-home',
templateUrl: 'home.html'
})
...

Ionic 3 Google Map click doc link
1.install this package
$ ionic cordova plugin add https://github.com/mapsplugin/cordova-plugin-googlemaps#multiple_maps --variable API_KEY_FOR_ANDROID="YOUR_ANDROID_API_KEY_IS_HERE" --variable API_KEY_FOR_IOS="YOUR_IOS_API_KEY_IS_HERE"
$ npm install --save #ionic-native/google-maps
2.Android and ios Api create
Go to this site - google cloud platform
3.After you got Api install packages
4.import
app.module.ts
import { GoogleMaps } from '#ionic-native/google-maps';
......
provider:[
GoogleMaps
];
5.home.html
<ion-header>
<ion-navbar>
<ion-title>
Ionic Blank
</ion-title>
</ion-navbar>
</ion-header>
<ion-content>
<div id="map"></div>
</ion-content>
6.home.ts
import { Component } from '#angular/core';
import { NavController, Platform } from 'ionic-angular';
import {
GoogleMaps,
GoogleMap,
GoogleMapsEvent,
LatLng,
CameraPosition,
MarkerOptions,
Marker
} from '#ionic-native/google-maps';
#Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage {
constructor(public navCtrl: NavController,
private googleMaps: GoogleMaps,
public platform: Platform) {
platform.ready().then(()=>{
this.loadMap();
})
}
loadMap() {
// create a new map by passing HTMLElement
let element: HTMLElement = document.getElementById('map');
let map: GoogleMap = this.googleMaps.create(element);
// listen to MAP_READY event
// You must wait for this event to fire before adding something to the map or modifying it in anyway
map.one(GoogleMapsEvent.MAP_READY).then(
() => {
console.log('Map is ready!');
// Now you can add elements to the map like the marker
}
);
// create CameraPosition
let position: CameraPosition = {
target: {
lat: 43.0741904,
lng: -89.3809802
},
zoom: 18,
tilt: 30
};
// move the map's camera to position
map.moveCamera(position);
// create new marker
let markerOptions: MarkerOptions = {
//position: ionic,
title: 'Ionic'
};
map.addMarker(markerOptions)
.then((marker: Marker) => {
marker.showInfoWindow();
});
}
}

Related

Leaflet marker not appearing when using observables

map.component.ts
export class MapComponent implements AfterViewInit {
private map;
private centroid: L.LatLngExpression = [49.2827, -123.1207];
private initMap(): void {
this.map = L.map('map', {
center: this.centroid,
zoom: 12
});
const tiles = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 18,
minZoom: 3,
attribution: '© OpenStreetMap'
});
tiles.addTo(this.map);
}
constructor(private _dataService: DataService) {
}
ngAfterViewInit(): void {
this.initMap();
this._dataService.pigMessage$.subscribe(message => {
L.marker([49.2827, -123.1207]).addTo(this.map).bindPopup("test").openPopup();
console.log(message);
})
}
}
data.service.ts
import { Injectable } from '#angular/core';
import { Subject } from 'rxjs';
import { pigReportType } from './pigReport';
#Injectable({
providedIn: 'root'
})
export class DataService {
private _pigMessageSource = new Subject<pigReportType>();
pigMessage$ = this._pigMessageSource.asObservable();
sendPigData(message: pigReportType){
this._pigMessageSource.next(message)
}
constructor() { }
}
When I click on the submit button, data service sends a new piece of information into the observable and redirects back to the map component. The problem is the marker is not adding inside of the subscribe function in map.component.ts.
Additionally, I have checked that the .subscribe function works because it prints the correct message. The markers just do not appear on the map.
I have tried looking through the html and seeing if there is a duplicated map that is covering the map with the marker but there isn't. Also I have tried to call initMap inside of the .subscribe function but it doesn't work.
I'm hoping if someone can point me in the right direction because I have searched everywhere on the web for a solution but can't find it.

ArcGIS API for JavaScript 4.18.1 - Angular 11, Typescript, NPM

I am looking at ArcGIS Javascript API 4.18.1. But it is confusing, how I should add it to a new Angular 11 project. Is there an example project somewhere that shows the basic folder structure and getting a map setup in Angular 11? I want to get it set up with just ES modules using NPM.
https://developers.arcgis.com/javascript/latest/es-modules/
I did this:
npm install #arcgis/core
Then I added the following to app.component.ts
import WebMap from '#arcgis/core/WebMap';
import MapView from '#arcgis/core/views/MapView';
I am new to this. And It seems like all the documentation talks about React.
Then in the getting started with Map it has you enter a key:
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no" />
<title>ArcGIS API for JavaScript Tutorials: Display a map</title>
<style>
html,
body,
#viewDiv {
padding: 0;
margin: 0;
height: 100%;
width: 100%;
}
</style>
<link rel="stylesheet" href="https://js.arcgis.com/4.18/esri/themes/light/main.css">
<script src="https://js.arcgis.com/4.18/"></script>
<script>
require(["esri/config","esri/Map", "esri/views/MapView"], function (esriConfig,Map, MapView) {
esriConfig.apiKey = "YOUR-API-KEY";
const map = new Map({
basemap: "arcgis-topographic" // Basemap layer service
});
});
</script>
</head>
<body>
<div id="viewDiv"></div>
</body>
</html>
But these docs are not for Typescript. Do they have typescript docs somewhere? How do you add the Key with the new API 4.18.1 and Typescript and NPM and Angular 11?
This is what I came up with.
It is based off https://github.com/TheKeithStewart/angular-esri-components which uses the arcgis-js-api library
https://github.com/Esri/jsapi-resources/tree/master/esm-samples/jsapi-angular-cli has the basic setup instructions for using #arcgis/core in an Angular application
esri-map.component.scss:
#mapViewNode {
padding: 0;
margin: 0;
height: 100%;
width: 100%;
}
esri-map.component.ts:
import {
Component,
ElementRef,
Input,
OnInit,
NgZone,
OnDestroy,
ViewChild,
Output,
EventEmitter,
} from '#angular/core';
import config from '#arcgis/core/config';
import { EsriMapService } from './esri-map.service';
#Component({
// tslint:disable-next-line: component-selector
selector: 'esri-map',
template: '<div #mapViewNode></div>',
styleUrls: ['./esri-map.component.scss'],
})
export class EsriMapComponent implements OnInit, OnDestroy {
#ViewChild('mapViewNode', { static: true }) private elementRef!: ElementRef;
#Input() mapProperties!: any;
#Input() mapViewProperties!: any;
#Output() mapInit: EventEmitter<any> = new EventEmitter();
private mapView: any;
constructor(private zone: NgZone, private mapService: EsriMapService) {}
ngOnInit(): void {
config.assetsPath = 'assets/';
this.zone.runOutsideAngular(() => {
this.loadMap();
});
}
ngOnDestroy(): void {
this.mapView.destroy();
}
loadMap(): void {
this.mapService.isLoaded.subscribe((n: any) => {
this.mapView = n.view;
this.zone.run(() => {
this.mapInit.emit({ map: n.map, view: n.view });
this.mapInit.complete();
});
});
this.mapService.loadWebMap({
...this.mapProperties,
...this.mapViewProperties,
container: this.elementRef.nativeElement,
});
}
esri-map.service.ts:
import { EventEmitter, Injectable } from '#angular/core';
import MapView from '#arcgis/core/views/MapView';
import WebMap from '#arcgis/core/WebMap';
import Widget from '#arcgis/core/widgets/Widget';
import Layer from '#arcgis/core/layers/Layer';
export type Position =
| 'bottom-leading'
| 'bottom-left'
| 'bottom-right'
| 'bottom-trailing'
| 'top-leading'
| 'top-left'
| 'top-right'
| 'top-trailing'
| 'manual';
#Injectable({
providedIn: 'root',
})
export class EsriMapService {
map!: WebMap;
view!: MapView;
loaded = false;
isLoaded = new EventEmitter();
constructor() {}
loadWebMap(props: {
basemap: any;
container: any;
center: any;
zoom: any;
}): void {
this.map = new WebMap({ basemap: props.basemap });
this.view = new MapView({
container: props.container,
map: this.map,
center: props.center,
zoom: props.zoom,
});
this.loaded = true;
this.isLoaded.emit({
map: this.map,
view: this.view,
});
}
addLayer(layer: Layer, clearLayers?: boolean): void {
if (clearLayers) {
this.view.map.removeAll();
}
this.view.map.add(layer);
}
addWidget(
component: string | HTMLElement | Widget | any[],
position?: Position,
): void {
this.view.ui.add(component, position);
}
}
You would just instantiate the component like this:
<esri-map [mapProperties]="mapProperties" [mapViewProperties]="mapViewProperties" (mapInit)="onMapInit($event)">
</esri-map>
mapProperties sets the base map.
mapViewProperties sets the center and zoom.
mapInit lets you know when the map is loaded.
The service provides the map view for constructing the map.
You would then add your layers to the map view as usual.

Leaflet - import Geojson - Angular 6

i try to import GeoJson file to leaflet in angular's app 6.
With this solution my geojson is drawn in leafletmap but i have this error and i can't build my app. Someone know one solution ?
ERROR TS2345 Argument of type '{"type": string;"features":({"type":
string; "geometry": { "type: string : "coordinates": num...' is not
assignable parameter of type GeoJsonObject
Model.ts
export const Pdl = [ 'my geojson' ];
https://raw.githubusercontent.com/alanent/france-geojson/master/regions/pays-de-la-loire/departements-pays-de-la-loire.geojson
Component.ts
import { LeafletModule } from '#asymmetrik/ngx-leaflet';
import * as L from 'leaflet';
import {Pdl} from "../models/pdl.model";
#Component({
selector: 'app-geo',
templateUrl: './geo.component.html',
styleUrls: ['./geo.component.scss']
})
export class GeoComponent implements OnInit {
ngOnInit() {
var mapboxAccessToken = "...";
const myfrugalmap = L.map('frugalmap').setView([47.482019, -1], 7);
L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token=' + mapboxAccessToken, {
id: 'mapbox.light',
attribution: 'SOS'
}).addTo(myfrugalmap);
L.geoJSON(Pdl).addTo(myfrugalmap);
}
}
Maybe, i can hide the error ? what is the way ?
You need to do it the 'angular way' since you are using ngx-leaflet
Importing a json via import is a nightmare in my personal opinion so what I would do would be to fetch it using a get request when the map is loaded and then get a reference to the map object and add the geojson.
template:
import { HttpClient } from '#angular/common/http';
import * as L from 'leaflet';
..
map: L.Map;
json;
options = {
layers: [
L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 18, attribution: '...'
})
],
zoom: 7,
center: L.latLng(47.482019, -1)
};
constructor(private http: HttpClient) { }
onMapReady(map: L.Map) {
this.http.get('assets/departements.json').subscribe((json: any) => {
console.log(json);
this.json = json;
L.geoJSON(this.json).addTo(map);
});
}
template
<div leaflet style="height: 800px"
[leafletOptions]="options"
(leafletMapReady)="onMapReady($event)">
</div>
Demo

ngx-leaflet map zoom events not triggering

As per ngx-leaflet documentation link (leafletMapMoveEnd) and (leafletMapZoomEnd) are both exposed events.
I'm assuming that these events are exposed in the same DOM that the map is Initialized, and should be implemented like this:
<div
leaflet
[leafletOptions]="options"
(leafletMapReady)="onMapReady($event)"
(leafletMapMoveEnd)="onMapMove($event)"
(leafletMapZoomEnd)="onMapZoom($event)">
Is this the correct way to catch these events?
(leafletMapReady) seems to be working just fine.
However neither (leafletMapZoomEnd) or (leafletMapMoveEnd) seem to be triggering when I mess with the map it self.
I tried panning the map, as well as zooming in and out. Neither of those interactions cause the handleMapZoomEnd($event) handleMapMoveEnd($event) methods to be hit.
import { Component, Input, OnChanges, OnInit, Output, EventEmitter } from '#angular/core';
import * as fromLeafLet from 'leaflet';
import 'leaflet.markercluster';
#Component({
selector: 'map',
templateUrl: './map.component.html',
styleUrls: [
'./map.component.css',
'./extra-marker-icon.css'
]
})
export class MapComponent implements OnInit, OnChanges {
constructor(){}
onMapReady(map: fromLeafLet.Map): void {
this.map = map;
}
onMapZoom(event: any):void{
console.log('Zoom');
this.onMapDirty.emit();
}
onMapMove(event: any):void{
console.log('Move');
this.onMapDirty.emit();
}
}
In the Github repo for the #asymmetrik/ngx-leaflet ngcli tutorial, I added a branch demo/events that shows a really simple example of using the zoom/move events.
git clone git#github.com:Asymmetrik/ngx-leaflet-tutorial-ngcli.git
git checkout demo/events
The files of interest are:
./src/app/app.component.html
./src/app/app.component.ts
The template (below) contains two handlers, one for each of the leafletMapMoveEnd and leafletMapZoomEnd outputs:
<div class="map"
leaflet
[leafletOptions]="options"
(leafletMapReady)="onMapReady($event)"
(leafletMapMoveEnd)="handleMapMoveEnd($event)"
(leafletMapZoomEnd)="handleMapZoomEnd($event)"
></div>
The component (below) just prints to the console on these events. I removed mostly everything that's not necessary to demo the events working.
import { Component } from '#angular/core';
import * as L from 'leaflet';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: [
'./app.component.css'
]
})
export class AppComponent {
streetMaps = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
detectRetina: true,
attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
});
map: L.Map;
options = {
layers: [ this.streetMaps ],
zoom: 7,
center: L.latLng([ 46.879966, -121.726909 ])
};
onMapReady(map: L.Map): void {
this.map = map;
}
handleMapZoomEnd(map: L.Map):void{
console.log('onMapZoomEnd');
}
handleMapMoveEnd(map: L.Map):void{
console.log('onMapMoveEnd');
}
}

Angular 4 cannot read property nativeElement of undefined using ViewChild

I am simply trying to access an element within my Angular 4 template to place a Google Map but I keep getting a "cannot read property native element of undefined" error. I've seen other people asking similar questions but anything I've tried up to this point has not worked.
I get the same error when trying to access the element in both ngOnInit and ngAfterViewInit. I also tried using document.getElementById and that gives me a null error as well. I know its not a Google Maps error because I get the error trying to access the element outside of Google Maps.
I have the following inside home.component.ts (this is inside a specific home component, not within the main app module):
import { NgModule, Component, OnInit, AfterViewInit, ElementRef, ViewChild } from '#angular/core';
import { } from '#types/googlemaps';
#Component({
selector: 'home-page',
templateUrl: './home.html'
})
export class HomeComponent implements OnInit, AfterViewInit {
#ViewChild('gmap') el:ElementRef;
map: google.maps.Map;
public ngOnInit() {
// other component initialization code here
}
public ngAfterViewInit () {
let mapProp = {
center: new google.maps.LatLng(18.5793, 73.8143),
zoom: 15,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
this.map = new google.maps.Map(this.el.nativeElement, mapProp);
// this alone gives me the same error
setTimeout(() => {
console.log(this.el.nativeElement);
}, 0);
}
}
Inside the component template - home.component.html:
<div class="row">
<div class="col-md-12">
<div class="text-center">
<div #gmap style="width:100%;height:400px"></div>
</div>
</div>
</div>
Your component's templateUrl says './home.html' but you also mentioned the file name being home.component.html in "Inside the component template - home.component.html". Maybe that's your problem?
I had a loader on the page that was showing until all the data was returning on the page:
public getData() {
this.loading = true;
this.homeService.getData().subscribe(response => {
this.resort = response;
this.loading = false;
this.error = false;
this.getMap();
}, error => {
this.loading = false;
this.error = true;
});
}
So even though ngAfterViewInit was running, the data from the database still wasn't back by the time that function ran, which was why it wasn't able to find the element as the actual data was hidden from an *ngIf until this.loading was false. So to correct I'm just calling getMap() once the data has been returned, rather then in the AfterViewInit function.
I then had to wrap that getMap function in a setTimeout to ensure the *ngIf was loading the content data before I was trying to access the element as well:
public getMap() {
setTimeout(() => {
// accessing element here
});
}
Perhaps because HomeComponent has no #Component annotation?
For one thing, without #Component, there's no way for HomeComponent to know that home.component.html is its template, and if it doesn't know its template, it doesn't know #gmap is a view child. Simply matching templates to classes by naming convention or file location isn't enough.
Change the type to any
#ViewChild('gmap') el: any;

Categories