Angular 2 doesnt update view after changed value - javascript

Given following Angular 2 code finding current position and converting to human-readable string -> binding to input element:
html tempalte:
<input name="myAddr" [(ngModel)]="form.address" type="text">
<button (click)="findMyLocation()" class="ui location right blue icon button">
<i class="marker icon"></i>
</button>
Angular 2 code:
form: {
volume: number,
thickness: number,
density: number,
address: string
} = { address: '', volume: 0, thickness: 100, density: 300 };
findMyLocation(){
$('.location').addClass('loading');
navigator.geolocation.getCurrentPosition(position => {
this.geocoder.geocode({location: { lat: position.coords.latitude, lng: position.coords.longitude }}, (results, status)=>{
if(status == 'OK')
if(results[0]){
$('.location').removeClass('loading');
console.log('Addr: ' + results[0].formatted_address);
this.form.address = results[0].formatted_address;
}
})
}, fail => {
console.log(fail);
});
}
However when I click button, location(lat, lng) are converted to humar readable adress, and I can see output to console. But input element doesnt change. If I click again on button, element gets update as it should be.
Whats going on guys?

Bacause navigator.geolocation.getCurrentPosition is asynchromous function, you have to use ngZone.run to let angular rerender the models.
this.ngZone.run(function() {
this.form.address = results[0].formatted_address;
};)
Note: you have to import NgZone and inject it at your constructor.
UPD: there are two ways as i know:
ngZone.run()
ChangeDetectorRef.detectChanges()

Related

DEVExpress DXmap: how to refresh to current location (longitude and latitude)?

When I open my page in google maps with dxmaps, it refreshes automatically to a set location (ML_LATITUDE, ML_LONGITUDE). This corresponds to numbers (like 35.18, 44.12). However, I want the program when to refresh, to remain in the same position that my screen (or cursor) is at.
Here is the relevant code:
markers.push({
location: { lat: oData[item]['ML_LATITUDE'], lng: oData[item]['ML_LONGITUDE'] },
iconSrc: oData[item]['ICON'], //"Content/Icons/map-marker.png",
onClick: function (args) { },
tooltip: {
isShown: fisShown,
text: oData[item]['TOOLTIP']
}
});
}

Bing Maps infobox is undefined inside Angular component

I am creating a component in angular/typescript for a bing maps implementation. I went through the process to add an infobox to the map that would initially be not visible to the user. When the user clicks on any of the pushpins on the map the infobox is supposed to display.
However it does not and the property is shown as undefined.
Note: 'DataPoints' contains a list of objects that contains lat long coordinates and an arbitrary ID number.
import { Component, AfterViewInit } from '#angular/core';
import { DataPoint } from '../common/data-point'
import { DataPoints } from '../common/data-points'
#Component({
selector: 'app-simple-bing-map',
templateUrl: './simple-bing-map.component.html',
styleUrls: ['./simple-bing-map.component.css'],
providers: []
})
export class SimpleBingMapComponent implements AfterViewInit {
private map: any;
private infobox: any;
ngAfterViewInit() {
this.getMap();
}
populateMap(){
for(var i in DataPoints){
var pushpin = new Microsoft.Maps.Pushpin(new Microsoft.Maps.Location(DataPoints[i].Lat, DataPoints[i].Long) , null);
pushpin.metadata = {
title: "Test Pushpin",
description: DataPoints[i].ID,
};
//Add a click event handler to the pushpin.
Microsoft.Maps.Events.addHandler(pushpin, 'click', this.displayInfobox);
//place pushpin
this.map.entities.push(pushpin);
}
}
getMap() {
//check if Microsoft is available
if ((window as any).Microsoft && (window as any).Microsoft.Maps) {
//if it is available create map instance
this.map = new Microsoft.Maps.Map(document.getElementById('mapId'), {
credentials: 'Your Bing Maps Key Here',
});
//initialize infobox
this.infobox = new Microsoft.Maps.Infobox(this.map.getCenter(), {
title: 'Pushpins',
description: 'ID Number'
}
);
//hide infobox
this.infobox.setOptions({ visible: false })
//Assign the infobox to a map instance.
this.infobox.setMap(this.map);
this.populateMap();
}
//wait and try again
else {
setTimeout(() => { this.getMap() }, 1000);
}
}
displayInfobox(e) {
//hide any previous infobox
this.infobox.setOptions({ visible: false });
//Make sure the infobox has metadata to display.
if (e.target.metadata) {
//Set the infobox options with the metadata of the pushpin.
this.infobox.setOptions({
location: e.target.getLocation(),
title: e.target.metadata.title,
description: e.target.metadata.description,
visible: true
});
}
}
}
As stated earlier the map loads completely and works as it should. It is just after I enter the 'displayInfobox' method that things act weirdly.
To retain this inside displayInfobox method i would advice you using either bind method like:
Microsoft.Maps.Events.addHandler(pushpin, 'click', this.displayInfobox.bind(this));
or arrow function:
Microsoft.Maps.Events.addHandler(pushpin, 'click', (e) => this.displayInfobox(e));
For other solutions see
https://github.com/Microsoft/TypeScript/wiki/%27this%27-in-TypeScript

VueJs only show google map when location is set

So I'm trying to build a simple app that shows distance to locations on a Google map, from a user's current location.
I'm using Vue.js 1.0 and the vue-google-maps plugin.
I'm trying to center the Google map on user's location, but can only get the map to load if I hard code the longitude and latitude data in my application like this:
export default {
data: function data() {
return {
center:{ lat:28.2328382, lng: -3.298973987232 },
mapBounds: {},
usermarkers: [],
businessmarkers: [],
zoomControl: true,
mapTypeControl: true,
data: {
currentLocation: '',
search: {
lon: '',
lat: '',
unit: '',
order: 'asc',
distance: '',
type: ''
}
},
};
},
My map is rendered here:
<map :center.sync="center" :zoom.sync="zoom" :map-type-id.sync="mapType" :options="{styles: mapStyles}">
<marker v-for="m in usermarkers" :position.sync="m.position">
<info-window :position="center" :content="ifw2text"></info-window>
</marker>
<marker v-for="m in businessmarkers" :position.sync="m.position">
<info-window :position="center" :content="m.ifw2text"></info-window>
</marker>
</map>
Then in the ready function I grab the geolocation of the user via html5 and push the user's marker on to the map.
So what I'm now trying to do is dynamically center the location.
I wrapped my map html in a conditional statement like so
<div v-if="!data.center.lat && !data.center.lng">
<map :center.sync="center" :zoom.sync="zoom" :map-type-id.sync="mapType" :options="{styles: mapStyles}">
<marker v-for="m in usermarkers" :position.sync="m.position">
<info-window :position="center" :content="ifw2text"></info-window>
</marker>
<marker v-for="m in businessmarkers" :position.sync="m.position">
<info-window :position="center" :content="m.ifw2text"></info-window>
</marker>
</map>
</div>
in my data function I leave the center empty
data: function data() {
return {
center:'',
Then my ready function grabs the geolocation builds the center object and sets this.center correctly
ready () {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function(position) {
let centerObj ={};
centerObj.lat = position.coords.latitude;
centerObj.lng = position.coords.longitude;
this.center = centerObj;
this.usermarkers.push({
position: { lat:this.center.lat, lng: this.center.lng }
});
}.bind(this), function (error) {
if (error.code == error.PERMISSION_DENIED)
alert('Please Enable Location Services');
}.bind(this));
}
},
My console.log show the center.lat and center.lng are set but the map is still not being rendered. Shouldn't vue reload the virtual DOM when data like this is set, thus rendering the map? Am I missing something really simple or going about this the complete wrong way?

Angular Google Maps map click event works once

I've been having a problem very similar to this
However that persons question was never answered and my situation is subtly different.
I'm trying to add a click event to my map that will change the center of the map to the location of the click. My code to do this works great, but it only works once and then when I click again I get this error:
angular-google-maps.js:6815 Uncaught TypeError: Cannot read property 'click' of undefined
Here is my map object:
vm.map = {
center: {
latitude: l.latitude,
longitude: l.longitude
},
zoom: 13,
events: {
click: function(map, event, coords) {
vm.map = {
center: {
latitude: coords[0].latLng.lat(),
longitude: coords[0].latLng.lng()
},
};
$scope.apply();
}
}
};
And here's my html:
<ui-gmap-google-map center="location.map.center" zoom="location.map.zoom" draggable="true" options="tabLocations.map.options" events=location.map.events>
<ui-gmap-search-box template="'scripts/components/tab-locations/searchbox.tpl.html'" events="location.map.searchbox.events" parentdiv="'searchbox-container'"></ui-gmap-search-box>
<ui-gmap-marker ng-if="location.active" idKey="1" coords="location" options="{draggable: false, icon: 'images/icons/gps-marker-active.svg'}"></ui-gmap-marker>
<ui-gmap-marker ng-if="!location.active" idKey="1" coords="location" options="{draggable: false, icon: 'images/icons/gps-marker-inactive.svg'}"></ui-gmap-marker>
</ui-gmap-google-map>
After your first click you are redefining a brand new map with no click event:
vm.map = {
center: {
latitude: coords[0].latLng.lat(),
longitude: coords[0].latLng.lng()
},
};
This is overriding all the previous properties you had set before, which includes click.
Use setCenter instead:
click: function(map, event, coords) {
var latLng = new google.maps.LatLng(latitude: coords[0].latLng.lat(), latitude: coords[0].latLng.lng());
vm.map.setCenter(latLng);
}
Reference: Google Maps API

Google Maps for Angular directive not working in function

I'm attempting to use this Google Maps for AngularJS directive inside another function. The code works when I move $scope.map outside the function call and set the lat/lon statically. However, what I want to do is set the lat/lon dynamically within my function call.
Code below.
html:
<google-map center="map.center" zoom="map.zoom"></google-map>
Angular controller:
angular.module('StadiumCtrl', []).controller('StadiumController', function($scope, $rootScope, $routeParams, $sce, Stadia, Instagram, Weather) {
// pull stadium details from API based on routeParams
$scope.id = $routeParams.id;
Stadia.get($scope.id).success(function(response) {
$rootScope.logo = response.logo;
$scope.homeColors = {
"border": "2px solid " + response.sec_hex,
"box-shadow": "3px 3px 7px " + response.prim_hex,
"margin": "6px",
"padding": "0"
}
$scope.map = {
center: {
latitude: response.loc[1],
longitude: response.loc[0]
},
zoom: 8
};
// pass loc_id into Instagram API call
Instagram.get(response.loc_id).success(function(response) {
instagramSuccess(response.loc_id, response);
});
// pass city and state into Wunderground API call
Weather.get(response.city, response.state).success(function(response) {
$rootScope.temp = Math.round(response.current_observation.temp_f);
});
// Instagram API callback
var instagramSuccess = function(scope,res) {
if (res.meta.code !== 200) {
scope.error = res.meta.error_type + ' | ' + res.meta.error_message;
return;
}
if (res.data.length > 0) {
$scope.items = res.data;
} else {
scope.error = "This location has returned no results";
}
};
});
It looks like the google-maps directive needs an initial value when the directive gets linked. Once there is a default value it will respond to changes in that scope value.
You can see this in action with the following code:
$scope.map = {center: {latitude:0,longitude:0}, zoom: 0};
$timeout(function() {
$scope.map = {center: {latitude: 51.219053, longitude: 4.404418 }, zoom: 14 };
}, 1000);
which is demonstrated at http://plnkr.co/edit/szhdpx2AFeDevnUQQVFe?p=preview. If you comment out the $scope.map assignment outside the $timeout the map will no longer show up, but if you put line 3 back it in will update the map when the $timeout executes.
In your case, you should simply be able to add
$scope.map = {
center: {
latitude: 0,
longitude: 0
},
zoom: 0
};
just before you run Stadia.get($scope.id).success(function(response) {.

Categories

Resources