Getting Undefined, understanding this, that, events, Ionic, google maps and Firebase - javascript

I have some code that independently works, but when I put it together I get "Undefined" error at "this"
It surly have something to to with my lack of understanding JS this, that.
I get it to work in Ionic 1, but not in Ionic 2.
I have two events, "MAP_READY" from Maps and "key_entered" from Geofire.
I would we very thankful for guidance. Here is the essential parts of the code:
platform.ready().then(() => {
this.LOADMAP();
});
//---------Loading map ----------
LOADMAP(){
Geolocation.getCurrentPosition().then((position) => {
this.map = new GoogleMap('map', {
'backgroundColor': 'white',
'controls':....
...
...
}
this.map.on(GoogleMapsEvent.MAP_READY).subscribe(() => {
this.GETMARKERS();
},
(err) => {
console.log(err);
});
});
}
//-----Get markers from Geofire/Firebase
GETMARKERS(){
...
...
var geoQuery = geoFire.query({
center: [lat,lon],
radius: 3000
});
...
var onKeyEnteredRegistration=GeoQuery.on("key_entered",
function(key,location) {
this.ADDMARKER(location)
});
}
}
//-------Adding marker to map
ADDMARKER(location){
let markerOptions: GoogleMapsMarkerOptions =
{position: location,title:'Some title' };
this.map.addMarker(markerOptions) <-------------------- This gives error
.then((marker: GoogleMapsMarker) => {
marker.showInfoWindow();
});
}

the error may show here
this.map.addMarker(markerOptions)
but actual error is at
var onKeyEnteredRegistration=GeoQuery.on("key_entered",
function(key,location) { <---------- HERE
this.ADDMARKER(location)
});
}
}
Change your code to
var onKeyEnteredRegistration=GeoQuery.on("key_entered",
(key,location) =>{
this.ADDMARKER(location)
});
}
}
'function' will change the scope, that's why 'this' wont work inside the block.
Hope this helps! :)

Related

Vue Error: Uncaught (in promise) TypeError cannot read properties of null (reading 'Address')

There is an error on clicking on the map is triggered in, time. Arrives in Promise, null. Explain why this is happening? Thank you in advance:
onMapClick(e) {
if (e.latlng) {
this.post("/api/MapObjectItem/GetObjectInfoByLatLng", {
Lat: e.latlng.lat,
Lng: e.latlng.lng
}).then(result => {
if (this.jkh.isCreateEvent) {
this.jkh.selectedMessage = {
Address: result.Address,
Lat: result.Lat,
Lon: result.Lng,
UsersDataID: this.$auth.user.Id,
ObjectID: result.Id,
ToPublish: false
};
this.$refs.map.mapObject.setView([result.Lat, result.Lng], 18);
this.showDetails();
} else {
this.obj = result;
this.changeView();
}
});
}
This Error Promise
It is probably because the javascript is running before the DOM is loaded. ( see Related posts on the right side )
Try running the js inside a function attached to an event listener:
function init() {
// Run your javascript code here
}
// Run the 'init' function when the DOM content is loaded
document.addEventListener("DOMContentLoaded", init, false)

How can I bypass ESLint calling the Geolocation interface undefined in Typescript?

I am utilizing the Geolocation API to place a marker on a map, but ESLint is complaining that GeolocationPosition is undefined. Nevertheless, the code runs and gives me the expected result, but I want to clean my code for warnings. I am new to typescript and ESlint, so I am unsure where to go from here. Any suggestions? Code and image of warning follows.
import { Map } from 'leaflet';
import { iconLocation, setMarker } from './leafletMarker';
export function getUserPosition(callback : (position : GeolocationPosition) => void) {
function success(position : GeolocationPosition) {
callback(position);
}
function error() {
console.log('Unable to retrieve your location'); // change to alerts when Alert component is ready
}
if (!navigator.geolocation) {
console.log('Geolocation is not supported by your browser'); // change to alerts when Alert component is ready
} else {
navigator.geolocation.getCurrentPosition(success, error, { enableHighAccuracy: true });
}
}
export function handleMyPosition(map: Map) {
getUserPosition((userPosition: GeolocationPosition) => {
if (map) {
const { latitude, longitude } = userPosition.coords;
setMarker(map, latitude, longitude, { icon: iconLocation });
map?.setView([latitude, longitude], 9);
}
});
}
Don't use no-undef in TypeScript projects. Just disable the rule in your config, TypeScript does the same but better.

initializing 'marker-animate-unobtrusive' in Vue fails

I am trying to use marker-animate-unobtrusive but I keep getting this error:
I found another post on SO that talked about requiring the file after google has loaded but I do not know how to do that. in my component I have this:
import SlidingMarker from 'marker-animate-unobtrusive'
In my mounted method I have this:
SlidingMarker.initializeGlobally()
Any help is greatly appreciated
This is expected error since SlidingMarker extends google.maps.Marker class, GoogleMaps JavaScript API library needs to be loaded first, one option would to add a reference via index.html file:
<script src="https://maps.googleapis.com/maps/api/js?key=--KEY-GOES-HERE--"></script>
Another option would to utilize async JavaScript loader, e.g. scriptjs. The example for loading GoogleMaps JavaScript API and marker-animate-unobtrusive module could look like this:
created: function(){
get("https://maps.googleapis.com/maps/api/js?key=", () => {
const SlidingMarker = require('marker-animate-unobtrusive')
SlidingMarker.initializeGlobally()
const map = new google.maps.Map(document.getElementById('map'), this.mapOptions);
const marker = new SlidingMarker({
position: this.mapOptions.center,
map: map,
title: 'Im sliding marker'
});
});
}
Here is a demo for your reference
Update
With vue-google-maps library marker-animate-unobtrusive plugin could be integrated like this:
<template>
<div>
<GmapMap :center="center" :zoom="zoom" ref="mapRef"></GmapMap>
</div>
</template>
<script>
/* global google */
export default {
data() {
return {
zoom: 12,
center: { lat: 51.5287718, lng: -0.2416804 },
};
},
mounted: function() {
this.$refs.mapRef.$mapPromise.then(() => {
this.initSlidingMarker(this.$refs.mapRef.$mapObject)
})
},
methods: {
initSlidingMarker(map){
const SlidingMarker = require('marker-animate-unobtrusive')
SlidingMarker.initializeGlobally()
const marker = new SlidingMarker({
position: map.getCenter(),
map: map,
title: 'Im sliding marker'
});
google.maps.event.addListener(map, 'click', (event) => {
marker.setDuration(1000);
marker.setEasing('linear');
marker.setPosition(event.latLng);
});
}
}
}
</script>
<style>
.vue-map-container {
height: 640px;
}
</style>
Install the package google from npm this should fix it.

Repeat function failed in Angular

For my Angular Project, I generated a geolocation component and want to repeat a function findMe() to show the current location.
Part of code in the component.ts is given as below.
...
export class GeolocationComponent implements OnInit{
#ViewChild('gmap') gmapElement: any;
map: google.maps.Map;
isTracking = false;
marker: google.maps.Marker;
constructor(public globalvar: GlobalvarService) { }
ngOnInit() {
var mapProp = {
center: new google.maps.LatLng(-27.542211, 153.1226333),
zoom: 15,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
this.map = new google.maps.Map(this.gmapElement.nativeElement, mapProp);
setInterval(this.findMe(), 3000);
}
findMe() {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition((position) => {
this.showPosition(position);
console.log("find me");
});
} else {
alert("Geolocation is not supported by this browser.");
}
}
showPosition(position) {
this.globalvar.latitude = position.coords.latitude;
this.globalvar.longitude = position.coords.longitude;
let location = new google.maps.LatLng(position.coords.latitude,position.coords.longitude);
this.map.panTo(location);
if (!this.marker) {
this.marker = new google.maps.Marker({
position: location,
map: this.map,
title: 'Got you!'
});
}
else {
this.marker.setPosition(location);
}
}
...
In
ngOnInit(),
I use
setInterval(this.findMe(), 3000);
By checking the log, I see the findMe() is only called once, but not be repeated as that I expect.
I also tried changing findMe() ==> findMe
setInterval(this.findMe, 3000);
this time, the log repeatedly appears, however there is always a error:
ERROR TypeError: _this.showPosition is not a function
Could you please help how can I repeatedly calling findMe() and why the error happens?
The correct way to invoke the interval is with the function declaration setInterval(this.findMe, 3000);. As you noted, if you include the () it is only executed once.
One of the issues that comes up with setInterval is that it changes the this context of the executing function. To fix this, you need to force it to be constant.
constructor(public globalvar: GlobalvarService) {
this.findMe = this.findMe.bind(this);
}
Additional info:
Documentation
StackOverflow Question
You can just use an arrow function that preserves this context :
setInterval(() => this.findMe(), 3000);
You can use arrow function syntax to make it work.
ngOnInit() {
setInterval(() => {
this.findMe()
}, 4000);
}
findMe = () => {
console.log('found');
}
Arrow function is referencing this as Component at all times.
Example - https://stackblitz.com/edit/angular-wkv2he
Try
setInterval(() => {
this.findMe()
}, 3000);
But I think than better solution is to use Observable interval.
interval(3000).subscribe(res => {
this.findMe()
})
Or in older versions of Angular :)
Observable.interval(3000).subscribe(res => {
this.findMe()
})

Taking Screenshot Ionic framework

I'm building Ionic application that have geolocation (Google Api), but that's irelevant, in upper right corner is button which i want to make to take screenshot and automatically make popover with options to send that screenshot image via email, viber..., but i don't have an idea how to take that screenshot, I googled and googled without any luck, please help.
app.controller('MapCtrl', function($scope, $cordovaGeolocation, $ionicLoading, $ionicPlatform) {
$ionicPlatform.ready(function() {
$ionicLoading.show({
template: '<ion-spinner icon="bubbles"></ion-spinner><br/>Acquiring location!'
});
var posOptions = {
enableHighAccuracy: true,
timeout: 20000,
maximumAge: 0
};
$cordovaGeolocation.getCurrentPosition(posOptions).then(function (position) {
var lat = position.coords.latitude;
var long = position.coords.longitude;
var myLatlng = new google.maps.LatLng(lat, long);
var mapOptions = {
center: myLatlng,
zoom: 16,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById("map"), mapOptions);
$scope.map = map;
$ionicLoading.hide();
var marker = new google.maps.Marker({
position: myLatlng,
map: map,
title: 'Lokacija'
});
}, function(err) {
$ionicLoading.hide();
console.log(err);
});
});
});
Two options, as far as I can tell:
Use a third-party Cordova plugin, such as https://github.com/gitawego/cordova-screenshot - this will most likely include the application's UI elements too, though, which might not be what you want.
Perhaps a better idea would be to use the Google Static Maps API - you can pass the current parameters from your dynamic map to it, and it'll return an image version.
This should get you started: How to take a screen shot in ionic
After you received the picture from the plugin, you can just use ionic's popover service to display it there.
This below code should help
*The function will take screenshot and share popup
For More details you can visit SocialSharing and Screenshot Ionic offical page
import { SocialSharing } from '#ionic-native/social-sharing/ngx';
import { Screenshot } from '#ionic-native/screenshot/ngx';
constructor(
private socialSharing: SocialSharing,
private screenshot: Screenshot
) { }
share(){
this.platform.ready().then(() => {
this.screenshot.URI(80)
.then((res) => {
//this.socialSharing.share('df',res.URI,null)
this.socialSharing.share('',null,res.URI,null)
.then(() => {},
() => {
alert('SocialSharing failed');
});
},
() => {
alert('Screenshot failed');
});
});
}

Categories

Resources