Angular Leaflet Search control event - angularjs

I have an AngularJS application and I'm currently trying to access the "search_expanded" event of Leaflet Search control but having no luck.
Here's my code:
angular.module('myApp', [ 'leaflet-directive' ])
.controller('ShowMapCtrl', ["$scope", "leafletData", function ($scope, leafletData) {
// some code
leafletData.getMap().then(function(map) {
map.on('search_expanded', function(e){
alert("search control expannded");
});
});

The search_expanded event, and all the other events supported by L.Control.Search are fired on the actual control instance not on the map instance as you can see in the following example:
var controlSearch = new L.Control.Search({
layer: new L.LayerGroup()
}).on('search_expanded', function () {
console.log('search_expanded!')
}).addTo(map);
http://plnkr.co/edit/njeXYb4PfbaG3hppcgmO?p=preview

First off I would try to throw some exception handling in there:
leafletData.getMap().then(function(map) {
map.on('search_expanded', function(e){
alert("search control expannded");
}, function(reason) {
alert('Failed: ' + reason);
});
Also, instead of alert, I prefer to use console.log() especially with Angular applications.
leafletData.getMap().then(function(map) {
map.on('search_expanded', function(e){
console.log("search control expannded");
}, function(reason) {
console.log('Failed: ' + reason);
});

I came up with a sloppy workaround since the directive won't allow me to catch the search control events.
var expanded = false;
$scope.$on('leafletDirectiveMap.layeradd', function(){
$('input.search-input').focus(function(){
expanded = !expanded;
if(expanded)
{
console.log("search control expanded");
}
});
});

Related

addListener Google Maps in Mapbox

How can I put the type of addListener of google maps onto Mapbox instead of below one?
Thanks for the response!
stationI.addListener('click', function() {
SetStationInfo(this.title);
});
Herebelow is the full code:
for (var i=0;i<APIinfo.network.stations.length;i++){
popup = new mapboxgl.Popup({ offset: 25 })
.setText(APIinfo.network.stations[i].name); //Mapbox
var marker = new mapboxgl.Marker()
.setPopup(popup)
.setLngLat([APIinfo.network.stations[i].longitude, APIinfo.network.stations[i].latitude])
.addTo(map); //Mapbox
stationI.addListener('click', function() { //Google Maps
SetStationInfo(this.title);
});
}
Reading your code, not sure what stationI is, if it's a layer or an object.
But regarding the events in mapbox, you can do that with:
map.on('click', function(e) {
console.log('A click event has occurred at ' + e.lngLat);
});
you can also add the layer:
map.on('click', 'yourLayerId', function(e) {
console.log('A click event has occurred at ' + e.lngLat);
});

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.

Angular Leaflet Directive Not updating marker position

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.

How to display wait message in AngularJS while data loading?

I'm new in AngularJS and trying to find the way how to display wait message while data loading? I mean data starts loading, display message and remove it when data loading is done.
I've searched the internet but haven't found anything I need...
<div ng-if="data.dataLoading">
Loading...
</div>
JS
$scope.data.dataLoading = true;
return someService.getData().then(function (results) {
...
}).finally(function () {
$scope.data.dataLoading = false;
});
Depends from where you're loading the data. One solution I used was to create a LoadingService
app.factory('LoadingService', function($rootScope) {
return {
loading : function(message) {
$rootScope.loadingMessage = message;
},
loaded : function() {
$rootScope.loadingMessage = null;
}
}
}).controller('FooController', function($scope,$http,LoadingService) {
$scope.loadSomeData = function() {
LoadingService.loading('Data is loading');
$http.get('/data').finally(function() {
LoadingService.loaded();
});
};
});
Since I had only one place where the message was being displayed I could use RootScope to handle this. If you want to have a loading message multiple times you could write a directive also to handle this like Codezilla posted
Edit: does not work on version 1.3.0 . Use request/response interceptors.
If you want to listen to all requests globally and display a loading widget whenever there's a request pending, you can count the requests using request/response transformers. You simply add a counter and increase on a new request and decrease it on response. I use a provider for that:
$httpProvider
.defaults
.transformRequest
.push(function(data) {
requestNotificationProvider
.fireRequestStarted(data);
return data;
});
And the same for transformResponse. Then the same provider holds the information on how many requests are pending and you can use them in a directive. You can read (& copy/paste the code) a full blog post on that here:
http://www.kvetis.com/2014/01/angularjs-loading-widget.html There's a working demo in attached.
I've answered this question in this StackOverflow article, but here's a recap of what I did.
If you style your code correctly, and make sure all calls to a web service pass through one particular factory function, then you can make that factory function handle showing and hiding your "Please Wait" popup.
Here's the factory function which I use to call all of my GET web services:
myApp.factory('httpGetFactory', function ($http, $q) {
return function (scope, URL) {
// This Factory method calls a GET web service, and displays a modal error message if something goes wrong.
scope.$broadcast('app-start-loading'); // Show the "Please wait" popup
return $http({
url: URL,
method: "GET",
headers: { 'Content-Type': undefined }
}).then(function (response) {
scope.$broadcast('app-finish-loading'); // Hide the "Please wait" popup
if (typeof response.data === 'object') {
return response.data;
} else {
// invalid response
return $q.reject(response.data);
}
}, function (errorResponse) {
scope.$broadcast('app-finish-loading'); // Hide the "Please wait" popup
// The WCF Web Service returned an error.
// Let's display the HTTP Status Code, and any statusText which it returned.
var HTTPErrorNumber = (errorResponse.status == 500) ? "" : "HTTP status code: " + errorResponse.status + "\r\n";
var HTTPErrorStatusText = errorResponse.statusText;
var message = HTTPErrorNumber + HTTPErrorStatusText;
BootstrapDialog.show({
title: 'Error',
message: message,
buttons: [{
label: 'OK',
action: function (dialog) {
dialog.close();
},
draggable: true
}]
});
return $q.reject(errorResponse.data);
});
};
});
This would get called like this:
myApp.webServicesURL = "http://localhost:15021/Service1.svc";
var dsLoadAllEmployees = function (scope)
{
// Load all survey records, from our web server
$scope.LoadingMessage = "Loading Employees data...";
var URL = myApp.webServicesURL + "/loadAllEmployees";
return httpGetFactory(scope, URL);
}
Here's the "Please wait" control which I use on each page..
<please-wait message="{{LoadingMessage}}" ></please-wait>
... and its code looks like this...
myApp.directive('pleaseWait',
function ($parse) {
return {
restrict: 'E',
replace: true,
scope: {
message: '#message'
},
link: function (scope, element, attrs) {
scope.$on('app-start-loading', function () {
element.fadeIn();
});
scope.$on('app-finish-loading', function(){
element.animate({
top: "+=15px",
opacity: "0"
}, 500);
});
},
template: '<div class="cssPleaseWait"><span>{{ message }}</span></div>'
}
});
Using this structure, any of my Angular controllers can load data from a web service in just a few lines, and leave the factory to look after showing/hiding the "Please wait" message and to display any errors which occur:
$scope.LoadAllSurveys = function () {
DataService.dsLoadAllSurveys($scope).then(function (response) {
// Success
$scope.listOfSurveys = response.GetAllSurveysResult;
});
}
Nice, hey ?
I dont know if is the correct way, but I put on my template
<img id="spinner" ng-src="images/spinner.gif" ng-if="!data" >
<div ng-repeat="repo in repos | orderBy: repoSortOrder">...</div>

Bind this to the youtube api statechange

I have a question about 'this' when using the youtube player javascript api in a require.js and backbone app. The youtube iframe_api is being loaded in a require.js module which I'm not including below. Here's my code, which is all following the typical backbone extend layout for a view.
youTubePlayer: function() {
var player,
self = this,
i = 0;
self.videoArray = [];
if ($('.slidevideo').length) {
_.each($('.slidevideo'), function(el, i) {
var YTid = $(el).data('videoid');
self.player = new YT.Player('Player-' + YTid, {
videoId: YTid,
playerVars: {
enablejsapi: 1
}
});
self.videoArray.push(self.player);
});
};
setTimeout(function(){
_.each(self.videoArray, function(video) {
video.addEventListener("onStateChange", self.stateChange)
});
}, 5000);
},
stateChange: function(e){
console.log(e);
console.log(this);
}
The issue is that 'this' in the stateChange function loses it's reference to the backbone view and instead references the global window object where I've loaded the youtube API and the YT constructor. How do I keep 'this' scoped within the Backbone view? Thank you very much in advance.
Use _.bind:
video.addEventListener("onStateChange", _.bind(self.stateChange, self));

Resources