I want to add a button in info window. How can I access my service's functions in angular 2?
Example:
import {Injectable} from 'angular2/core';
#Injectable()
export class MapService {
private map: any;
constructor() { }
initialize(): void {
this.map = new google.maps.Map(document.getElementById("map"), {
center: new google.maps.LatLng(33.751222, 33.98131),
zoom: 10,
mapTypeId: google.maps.MapTypeId.ROADMAP
});
}
addMarker(): void {
let marker = new google.maps.Marker({
position: new google.maps.LatLng(33.751222, 33.98131),
map: this.map
});
let infoWindow = new google.maps.InfoWindow({
content: `<h6>Content</h6><button onclick="foo()">Click me</button>`
});
google.maps.event.addListener(marker, 'click', () => {
infoWindow.open(this.map, marker);
});
}
foo() {
console.log('Clicked!');
}
}
This example, obviously, doesn't work: "ReferenceError: foo is not defined". How can I make this button work?
Thanks!
foo is searched on the window object.
I would use the approach explained in
How do expose angular 2 methods publicly?
to get a method of your service called.
If it were a component or directive instead of a service I would rather use this approach https://stackoverflow.com/a/36832108/217408
but you can also register an event handler imperatively like window.addEventHandler('my-custom-event', onMyCustomEvent) so the 2nd approach would also work with your service.
Related
I'm trying to replicate the Importing Data into Maps (Importing Data into Maps) example to my angular project but I get the following error in console:
earthquake_GeoJSONP.js:1 Uncaught ReferenceError: eqfeed_callback is not defined
at earthquake_GeoJSONP.js:1:1
app.component.ts
import { Component, OnInit } from '#angular/core';
import { Loader } from "#googlemaps/js-api-loader"
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit{
title = 'map';
ngOnInit() {
let map: google.maps.Map;
const loader = new Loader({
apiKey: "YOUR_API_KEY"
});
loader.load().then(() => {
const map = new google.maps.Map(document.getElementById("map") as HTMLElement, {
zoom: 2,
center: new google.maps.LatLng(2.8, -187.3),
mapTypeId: "terrain",
});
// map.data.loadGeoJson('data.json');
// Create a <script> tag and set the USGS URL as the source.
const script = document.createElement("script");
// This example uses a local copy of the GeoJSON stored at
// http://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/2.5_week.geojsonp
script.src =
"https://developers.google.com/maps/documentation/javascript/examples/json/earthquake_GeoJSONP.js";
document.getElementsByTagName("head")[0].appendChild(script);
const eqfeed_callback = function (results: any) {
for (let i = 0; i < results.features.length; i++) {
const coords = results.features[i].geometry.coordinates;
const latLng = new google.maps.LatLng(coords[1], coords[0]);
let marker = new google.maps.Marker({
position: latLng,
map: map,
});
// place marker in map
marker.setMap(map)
}
};
});
}
}
app.component.html
<div id="map"></div>
app.component.css
#map {
height: 500px;
width: 100%;
}
Installed Packages
This is the googlemaps package that I installed in my project.
npm install #googlemaps/js-api-loader
npm i -D #types/google.maps
My Angular version
Angular CLI: 13.3.7
Node: 16.14.2
Package Manager: npm 8.5.0
OS: win32 x64
What my code shows
Just appear the map but without markers.
What I hope will appear
According to the Google Maps documentation at the following link: Importing Data into Maps
Thanks for your time and support!
I confirmed that your map appears but the markers don't.
Just like you said, what you want to happen is for the markers to show.
What I did is I tried to replicate your code in codesandbox and found out two main errors:
'map' is defined but never used. (#typescript-eslint/no-unused-vars)
'eqfeed_callback' is assigned a value but never used. (#typescript-eslint/no-unused-vars)
Solutions:
Error #1: app.component.ts had an unused variable of map and it looks like this in your code:
ngOnInit() {
let map: google.maps.Map;
const loader = new Loader({
apiKey: "YOUR_API_KEY"
});
loader.load().then(() => {
const map = new google.maps.Map(document.getElementById("map") as HTMLElement, {
zoom: 2,
center: new google.maps.LatLng(2.8, -187.3),
mapTypeId: "terrain",
});
the map variable inside the loader.load().then is the one you used and the one on top is the unused which caused error #1. I just removed it and it removed the error on the console.
Error #2: your code had a variable eqfeed_callback that stored a function but was not called. I compared your code to the sample you gave here and confirmed that there was a callback on the code there.
As I am not very familiar to typescript and angular I tried experimenting on the code and made it work by making the end part of your code look like this:
const eqfeed_callback = function (results: any) {
for (let i = 0; i < results.features.length; i++) {
const coords = results.features[i].geometry.coordinates;
const latLng = new google.maps.LatLng(coords[1], coords[0]);
let marker = new google.maps.Marker({
position: latLng,
map: map
});
// place marker in map
marker.setMap(map);
}
};
window.eqfeed_callback = eqfeed_callback;
});
}
}
I just inserted window.eqfeed_callback = eqfeed_callback and it made the error disappear and at the same time show the markers on the map.
Here's the sandbox link: https://codesandbox.io/s/holy-sound-p8qtrc
Just use your own API key.
I hope this helps.
This is error which I don't understand TypeError: Cannot read properties of undefined (reading 'getCameraForLocationToPoint')
I got this error when I try to create a Bingmap for my angular project
.TS
let loc = new Microsoft.Maps.Location(Latitude,Longitude);
this.map.setView({ center: { latitude: loc.latitude, longitude: loc.longitude }});
this.map.setView({ mapTypeId: Microsoft.Maps.MapTypeId.streetside });
Microsoft.Maps.Events.addHandler(this.map, 'viewchangeend', () => { this.updateView(this.map); });
this.updateView(this.map);
Microsoft.Maps.Events.addHandler(this.map, 'click', this.Clicked.bind(this.map));
streetViewMapPromise(promise: Promise<any>) {
promise.then(x => {
this.map = x;
})
}
Clicked(e){ //click event
console.log(e)
}
.Html
<app-rs-bingmap (MapPromise)="streetViewMapPromise($event)" [options]="_mapOptions"></app-rs-bingmap>
above section is my Bingmap v8 component import section. As well as my click event is not working too. when I click on the map I want to show and alert.
Here is the stackblitz : getCameraForLocationToPoint error here
I am trying to implement Marker Clusterer in my app. I installed '#google/markerclusterer' in my project and have imported it as shown below. However, I am receiving the error: core.js:4002 ERROR TypeError: _google_markerclusterer__WEBPACK_IMPORTED_MODULE_7__ is not a constructor. I have no clue why I am getting this since it should be a constructor. Here is my code.
import * as MarkerClusterer from '#google/markerclusterer';
Within initMap()
for (var i = 0; i < features.length; i++) {
const infowindow = new google.maps.InfoWindow({
content: features[i].content
});
const marker2 = new google.maps.Marker({
position: features[i].position,
icon: icons[features[i].type].icon,
animation: google.maps.Animation.DROP,
map: map
});
marker2.addListener('click', () => {
marker2.setAnimation(google.maps.Animation.BOUNCE);
setTimeout(() => {
marker2.setAnimation(null);
}, 1000);
infowindow.open(map, marker2);
});
const markerCluster = new MarkerClusterer(map, marker2,
{ imagePath: 'https://developers.google.com/maps/documentation/javascript/examples/markerclusterer/m' });
}
<script src="https://unpkg.com/#googlemaps/markerclusterer/dist/index.min.js"></script>`
Use this and in your function initMap
const markerCluster = new markerClusterer.MarkerClusterer({ map, markers });
It's a typeError. Typescript doesn't know how to locate the typings. Have your tried #types/markerclustererplus?
Whenever I install a library I always try to make sure to look for the types. And also, like Google Analytics & Googlemaps can be a pain so adding them to tsconfig.json in src/tsconfig.json helps:
"types": [
"googlemaps",
"google.analytics",
"node"
]
And in a typings.d.ts file in your project root folder:
declare var MarkerClusterer: any;
declare module 'google-maps' {
export = google.maps;
}
Or put it between your
import { ... } from '#angular/core';
declare var MarkerClusterer: any;
#Component()
if you don't want to do the typings.d.ts or src/tsconfig.json. Try different options. Angular/Typescript is finicky.
To make the comment from #MukulSharma more prominent. Instead of this
import * as MarketClusterer '#google/markerclusterer'
do this
import MarkerClusterer from '#google/markerclusterer'
I'm building an angular application using openlayers that when I click a button it will recenter my map .I'm trying to re-center my map when I onClick to a button but it doesnt work.
ERROR TypeError: Cannot read property 'setCenter' of undefined.
Can someone tell me what I'm doing wrong. Thanks in advance !
import { Component } from '#angular/core';
import {fromLonLat} from 'ol/proj'
import {view} from 'ol/View';
import * as ol from 'openlayers';
export class AppComponent {
distance = 60;
points: Array<{ x: number; y: number; }> = [];
position : Array<{ x: number; y: number; id: string; radius: number,color:string, place:string}> =
[
{x:11.5820,y:48.1351,id:"munich",radius:20, color:"red", place:"m"},
{x:13.388866,y:52.517071,id:"berlin", radius:40,color:"blue", place:"b"},
];
coords = {
berlin: [13.388866, 52.517071]
};
onClick (city: string) {
view.setCenter({
center: fromLonLat(this.coords[city]),
duration: 2000
});
}
mapOnClick(evt) {
console.log(evt);
const map = evt.map;
// this bit checks if user clicked on a feature
const p = map.forEachFeatureAtPixel(evt.pixel,
function(feature, layer) {
console.log("got feature" + feature.getId());
return feature;
});
}
}
<button id='berlin' (click)="onClick('berlin')">Zoom to Berlin</button>
If you are trying to recenter there must already be a view, but if it was constructed inside the map constructor there won't be a view variable and you will need to reference it using map.getView(). Also setCenter() doesn't do animated recentering. Assuming your map variable is map try:
map.getView().animate({
center: fromLonLat(this.coords[city]),
duration: 2000
})
Lets try this once just for suggestion,
import OlView from 'ol/View';
view: OlView;
ngOnInit() {
this.view = new OlView({
center: fromLonLat(this.coords[city]),
zoom: 3
});
}
I hope its solve your problem if you received proper data for this.coords[city] variable. You need to pass data like this, center: fromLonLat([6.661594, 10.32371]).
For more Reference,
Use OpenLayers 4 with Angular 5
You may get some idea from this above url example.
Thanks,
Muthukumar
I created the following setup
HTML
<div class="col-md-6">
<div id="GISMap" v-el:map></div>
</div>
main.js VUE
var Vue = require('vue');
import VueResource from 'vue-resource';
import HomeView from './components/HomeView.vue';
Vue.use(VueResource);
Vue.config.debug = true;
window.app = new Vue({
el: '.content',
components: {
HomeView
},
methods: {
// Broadcast info that API has been loaded. Listen to this in GoogleMaps Module
init: function() {
this.$broadcast('MapsApiLoaded');
}
}
})
MODULE 1: HomeView.vue
<script>
export default {
events: {
MapsApiLoaded: function() {
// Initialize GIS Map
initGISMap(this.$els.map);
}
}
}
</script>
GoogleMaps.js
function initGISMap(selector) {
map = new google.maps.Map(selector, {
zoom: 10,
mapTypeId: google.maps.MapTypeId.ROADMAP,
});
// Set initial Location and center map to this location
initialLocation = new google.maps.LatLng(48.184845, 11.252553);
map.setCenter(initialLocation);
// Create a searchmarker
searchMarker = createMarker();
// Init Autocomplete for GIS
initAutoComplete();
}
I want to create the map in the div container with the tag v-el:map. When I call initGISMap(this.$els.map) within the module, and print out the value in the console, it is empty. So it seems that I don't have access to this element from within a module? How do I need to change this?
Overall approach:
main.js init() method is broadcasting an info when the map is loaded. This is caught within the HomeView module and the initGISMap is supposed to be called, residing in the GoogleMaps.js. This is all working fine, but the element to be handed over is missing.
The element is probably not in the scope of your HomeView module.
The good thing is: vm.$broadcast() can take more than one argument, so you can pass the element directly to the function with
this.$broadcast('MapsApiLoaded', this.$els.map);
and in HomeView.vue, you can pass it on with
export default {
events: {
MapsApiLoaded: initGISMap;
}
}
(You don't have to wrap initGISMap in a closure here.)