Angular Leaflet Directive Not updating marker position - angularjs

I'm trying to use angular-leaflet-directive with Websocket, though I'm able to integrate successfully, the positions of the markers are not getting updated dynamically. However The positions of map gets updated if I move mouse over the map but doesn't get updated when the lat-lng value changes.
Below is code snippet of module.
$scope.markers = {};
angular.extend($scope, {
bounds : $scope.bounds,
center : {},
kppaths : {},
events: {
markers:{
enable: [ 'move' ]
}
}
});
$stomp.setDebug(function(args) {
$log.info(args);
});
$scope.startWS = function() {
var connectionHeaders = {};
// Connect
$stomp.connect("/kp-ws").then(function(frame){
$log.info("connected to server")
$stomp.send('/app/start', {});
// Subscribe for message
$scope.subscription = $stomp.subscribe('/topic/kp', function(
data, headers, res) {
angular.forEach(data, function(k,v){
$scope.markers[k.markerId].lat = k.lat;
$scope.markers[k.markerId].lng = k.lng;
});
});
});
};
$scope.stopWS = function() {
$stomp.send('/app/stop', {});
$scope.subscription.unsubscribe();
$stomp.disconnect();
};
$scope.$on("leafletDirectiveMarker.move", function(event, args){
$log.info(args.model.lat);
});
} ]);
The html file
<div class="card-block">
<leaflet bounds="bounds" geojson="geojson" lf-center="center"
paths="kppaths" markers="markers" event-broadcast="events" width="100%" height="480px"></leaflet>
</div>
Is I'm missing something, Please let me know or suggest how to fix this issue?

The possible workaround I found is:
leafletData.getMap().then(function (map) {
$timeout(function() {map.invalidateSize()});
});
basically, once the map is invalidated, it updates markers' position. Although not perfect, considering some performance issues, the workaround at least solves the main issue.

Related

Implementing notification alerts in angularjs

I was wondering how an error alert would be implemented using angularjs.
Required functionality:
An alertQueue consists of all the alerts to be displayed to the user. These alerts are deleted from the queue after a span of 3 seconds. The user himself can close the alert by clicking the close button.
This AlertService must be the core service. Alerts are rendered in the view as <alert-list></alert-list>i.e using a component alertList.
Should be able to update alerts from other controllers like: AlertService.alert("my alert").
so far what I have done?
angular.
module('core').
factory('AlertService', [function() {
var alertQueue = [];
var addAlert = function(message, type){
message = {message: message, type: type};
alertQueue.push(message)
};
var deleteAlert = function(alert){
alertQueue.splice(alertQueue.indexOf(alert), 1);
};
return{
warning: function(msg){
addAlert(msg, "warning");
},
success: function(msg){
addAlert(msg, "success");
},
removeAlert: function(alert){
deleteAlert(alert);
},
getAlerts: function(){
return alertQueue;
}
}
}]);
angular.
module('alertApp').
component('alertList', {
templateUrl: '/static/js/app/aurora-alert/aurora-alert.template.html',
controller: ['$routeParams','$scope', 'Aurora',
function AlertController($routeParams, $scope, AlertService) {
var self = this;
self.alertQueue = AlertService.alertQueue;
self.alert = function(){
var message = arguments[0];
AlertService.warning(message);
};
self.removeAlert = function(alert) {
AlertService.removeAlert(alert);
};
}
]
});
I know that I'm doing something wrong in the above code and in its logic. I said above that I require the <alert-list></alert-list> component. So the alertService is injected as a dependency into alertController. But how am I going to raise the alert from other controllers? I know we can use $scope.$broadcast but that doesn't feel right.
Please explain how to achieve this? No third party libraries are to be used.
I think you are going about it only slightly incorrectly. Your alert-list should be responsible only for displaying and removing alerts, not for creating them. Leave the creation of alerts to your controllers
So for example, if you run into an error with an ApiSerivce:
DemoCtrl(AlertService, ApiService) {
ApiService.submitForm({some:data}).then(function() {
//something successfull happened
}).catch(function(error) {
AlertService.warning("Something bad happened calling the API serivce");
});
}
Then you can change your AlertService to broadcast an event when a new alert is created that the alert-list can listen to:
factory('AlertService', ["$rootScope", function($rootScope) {
var alertQueue = [];
var addAlert = function(message, type){
message = {message: message, type: type};
alertQueue.push(message)
$rootScope.$broadcast("new-alert"); //notify the list that there are new alerts
};
This is how you would listen to it in your alert-list:
$scope.$on("new-alert", function() {
self.alertQueue = AlertService.alertQueue;
});
This way, as soon as an alert is created, the alert-list is instantly updated with the latest queue of alerts.
You would probably want to do the same thing for alert deletion.

Atmosphere and Angular JS how to

I'm an atmosphere & Angular newbie and I'm really struggling to find an answer to this! Maybe I'm asking the wrong question.
I am setting up notifications using Atmosphere. I can open the websocket and watch the updates happen if I post the API URL directly into my browser.
In Angular I have an ng-repeat loop, which I would like to run as each new update adds a new object to the websocket.
<li ng-repeat="notification in notifications track by $index">
I am using angular watch to check for updates, but it doesn't pick up the new objects being added to the array. Here is my code:
// notification alerts
$scope.notifications = [];
notificationsService.notificationAlerts().then(function success(response) {
var jsonStringArray = response.data.split('|');
$scope.notifications = $.map(jsonStringArray, function(n, i){
if (n !== ""){
return JSON.parse(n);
}
});
console.log('Connect', response);
});
$scope.$watch('notifications', function(newVal, oldVal){
console.log('Watch', $scope.notifications);
}, true);
Hopefully I've made myself clear, let me know if I need to elaborate, or if I'm asking the wrong question. Thanks!
OK, I managed to solve this, for anyone stumbling across it later. Here is the final JS:
// add number of notifications to ".notifications-number"
function updateNumberOfNotifications(){
var numberOfNotifications = $("ul.notifications-list li").not(".nocount").length;
if (numberOfNotifications < 1) {
$(".notifications-number, .notifications-list").addClass("hidden");
} else {
$(".notifications-number").html(numberOfNotifications);
$(".notifications-number, .notifications-list").removeClass("hidden");
}
}
// notification alert variables
$scope.notifications = [];
var socket = atmosphere;
var subSocket;
// subscribe
function subscribe() {
var request = {
url : "/service/notifier",
transport: 'long-polling'
};
request.onMessage = function (response) {
//console.log('response', response);
var jsonStringArray = response.responseBody.split('|');
// console.log('json string array', jsonStringArray);
$.each(jsonStringArray, function(index, elem){
if (elem != ""){
$scope.notifications.push(JSON.parse(elem));
console.log("object", JSON.parse(elem));
}
});
//$scope.notifications.push($scope.newNotification);
$scope.$apply();
updateNumberOfNotifications();
// console.log('$scope.notifications', $scope.notifications);
};
subSocket = socket.subscribe(request);
}
function unsubscribe(){
socket.unsubscribe();
}
// subscribe on load and update notifications
updateNumberOfNotifications();
subscribe();

Google Maps Angular loop through callback to show multiple markers

I'm trying to display markers on a map, but I am running in to difficulty, I'm not too skilled in the use of callbacks, can someone help me out thanks? I want multiple markers to show where different games are.
I'm using a rest api to retrieve the game details from the db, and I know this works, it's just after I retrieve them I can no longer access the data that has just been retrieved.
I am using ionic (Angular) and I am sure there is probably a better way of doing this. What is the best way to use a loop? If anyone could point out how I could improve my code. Here is what my controller for the map looks like
.controller('MapController', function($scope, $ionicLoading, gameFactory) {
$scope.initialise = function() {
...//set up map
});
$scope.map = map;
};
$scope.showGameMarkers = function() {
var map = document.getElementById("map");
gameFactory.getGames().success(function(data) {
//at this stage the data variable contains the details of my game
angular.forEach(data, function(key, data) {
//now data is empty
var latLng = new google.maps.LatLng(data.locationLatitude, data.locationLongitude);
console.log("latlang = "+latLng);
// Creating a marker and putting it on the map
var marker = new google.maps.Marker({
position: latLng,
title: data.locationName,
setMap : map
});
});
}).error(function(data) {
console.log("no games");
});
};
google.maps.event.addDomListener(document.getElementById("map"), 'load', $scope.initialise());
google.maps.event.addDomListener(document.getElementById("map"), 'load', $scope.showGameMarkers());
});
Thank you in advance!
It looks like you might have your key and data parameters reversed in your forEach loop. According to https://docs.angularjs.org/api/ng/function/angular.forEach it should be
angular.forEach(values, function(value, key) {
...
}

how to use GooglePlacesServices with angular-google-maps

I have a map and search-box instantiated and dropping a marker after search is completed. This is working properly, however, I want to query the places services to get places nearby where my marker is dropped and I am getting an error that when running: google.maps.places.PlacesService(map) Uncaught TypeError: undefined is not a function...
Below is some relevant code
In my Angular.module.config:
uiGmapGoogleMapApiProvider.configure({
v: '3.17',
libraries: 'places'
});
In my maps controller:
1) callback when loaded
uiGmapGoogleMapApi.then(function(maps) {
$scope.googleMapsObject = maps;
});
2) setup the event handler to create the marker
$scope.searchbox = {
events: {
places_changed: placesChangedHandler
}
}
3) handle when places are changed, set the marker for lat, and (LAST LINE IS THE PROBLEM) query for the name of the place.
function placesChangedHandler(searchBox) {
var lat = searchBox.getPlaces()[0].geometry.location.k;
var lgn = searchBox.getPlaces()[0].geometry.location.C;
var center = { latitude: lat , longitude: lgn };
$scope.address = searchBox.getPlaces()[0].adr_address;
$scope.map = {
center: center, zoom: 15
};
setMarker(center);
var service = new google.maps.places.PlacesService($scope.googleMapsObject);
// service.nearbySearch(request, callback);
}
The error is on that second to last line. (also, is there a cleaner way to get to those variables?)
Thanks in advance for your help!
I faced the same problem recently and it took time to understand what is wrong because I'm new to angular (to be honest I'm new to Java Script;) )
In your controller you need add $window dependency to access global object google. Here is how it can look like:
.controller('mapCtrl', ['$scope', '$window', 'uiGmapGoogleMapApi'
, function($scope, $window, GoogleMapApi) {
GoogleMapApi.then(function(map) {
$scope.googleVersion = map.version;
$scope.map = { center: { latitude: 59.9500, longitude: 10.7500 }, zoom: 11 };
$scope.googleMapsObject = map
var service = new $window.google.maps.places.PlacesService($scope.googleMapsObject);
});
}])
I think the issue is you are trying to load the places service on the "maps" returned value which is the google.maps object.
so:
$scope.googleMapsObject == google.maps
what you need is to either use the markers directive (which I havent tried yet) or go on the actual map object for your map which you can get from the tilesLoaded event.
$scope.map = {
events: {
tilesloaded: function (map) {
$scope.$apply(function () {
$scope.actualMapObj = map;
$log.info('this is the map instance', map);
});
}
}
}
tilesLoaded from faq: http://angular-ui.github.io/angular-google-maps/#!/faq
After you initialize it with 'places' as library you should have the places property in the api parameter
uiGmapGoogleMapApi.then(function(maps) {
maps.places.PlacesService() // -> here you can search for something
});

How to check internet connection in AngularJs

This is how I would check internet connection in vanilla javascript:
setInterval(function(){
if(navigator.onLine){
$("body").html("Connected.");
}else{
$("body").html("Not connected.");
}
},1000);
I have angular controllers and modules in my project. Where should I put the code above? It should be executed in global context and not be assigned to a certain controller. Are there some kind of global controllers maybe?
First of all, I advise you to listen to online/offline events.
You can do it this way in AnguarJS:
var app = module('yourApp', []);
app.run(function($window, $rootScope) {
$rootScope.online = navigator.onLine;
$window.addEventListener("offline", function() {
$rootScope.$apply(function() {
$rootScope.online = false;
});
}, false);
$window.addEventListener("online", function() {
$rootScope.$apply(function() {
$rootScope.online = true;
});
}, false);
});
NOTE: I am wrapping changing of root scope's variable in $apply method to notify Angular that something was changed.
After that you can:
In controlller:
$scope.$watch('online', function(newStatus) { ... });
In HTML markup:
<div ng-show="online">You're online</div>
<div ng-hide="online">You're offline</div>
Here is a working Plunker: http://plnkr.co/edit/Q3LkiI7Cj4RWBNRLEJUA?p=preview
Other solution could be to broadcast online/offline event. But in this case you need to initialize current status upon loading and then subscribe to event.
It's definitely not as nice, but you could just try an AJAX request to your web server; it'll either succeed or time out.
Also, the HubSpot/offline project looks really good.
Your options:
addEventListener on the window, document, or document.body.
setting the .ononline or .onoffline properties on document or
document.body to a JavaScript Function object.
specifying ononline="..." or onoffline="..." attributes on the tag in
the HTML markup
I will demonstrate the easiest.
In you controller
document.body.onoffline = function() {
alert('You are offline now');
$scope.connection = 'offline'
}
document.body.ononline = function() {
alert('You are online again');
$scope.connection = 'online'
}
Check $scope.connection variable before you try to send requests around.
For Angular 2+ you can use ng-speed-test:
Just install:
npm install ng-speed-test --save
Inject into your module:
import { SpeedTestModule } from 'ng-speed-test';
#NgModule({
...
imports: [
SpeedTestModule,
...
],
...
})
export class AppModule {}
Use service to get speed:
import {SpeedTestService} from 'ng-speed-test';
#Injectable()
export class TechCheckService {
constructor(
private speedTestService:SpeedTestService
) {
this.speedTestService.getMbps().subscribe(
(speed) => {
console.log('Your speed is ' + speed);
}
);
}
}

Resources