Saving user input from Popup in local storage not working properly - leaflet

i have a marker with pop i was able to save user input from a form in my popup but the problem is it will only save if i have to click somewhere on the map first. heres my code...
L.marker([63.233627, 5.625])
.addTo(map)
.bindPopup('<form><select class="fodd" id="fodd-1"><option value="false">false</option><option
value="true">true</option></select><button type="button" id="btnInsert">Save</button></form>')
.on('click', foddStatus);
L.marker([72.181804, 45])
.addTo(map)
.bindPopup('<form><select class="fodd" id="fodd-2"><option value="false">false</option><option
value="true">true</option></select><button type="button" id="btnInsert">Save</button></form>')
.on('click', foddStatus);
function foddStatus(e) {
var btnInsert = document.getElementById("btnInsert");
btnInsert.onclick = function () {
// get user input when button is saved is clicked
var foddValue = document.querySelector('.fodd').value;
var foddLoc = document.querySelector('.fodd').id;
var midFodd = ":";
var var1 = foddLoc + midFodd;
var new_data = foddLoc + midFodd + foddValue;
console.log(new_data);
// if there is nothing saved on storage then save an empty array
if (localStorage.getItem('foddstatus') == null){
localStorage.setItem('foddstatus','[]');
}
// get old data and slap it to the new data
var old_data = JSON.parse(localStorage.getItem('foddstatus'));
old_data.push(new_data);
// save the old + new data to local storage
localStorage.setItem('foddstatus', JSON.stringify(old_data));
// console.log(key);
}
}
so what happens here on the first marker that I click the save button, it will save the values in localstorage, then when I go to the second marker and click the save button, it won't actually save on local storage. I have to click somewhere else on the map first in order to save the second marker's input on my localstorage.

this is a bit other approach to achive your goal, but maybe it helps.
This is only a test, without any validation etc. so please be aware of it!
I used here simple divs in the popups, inside an input and a button. Every button has its onclick attribute to call storeData function, which sets the localStorage key-value if the input is not empty. I used the input ids as keys.
The example snippet:
let ls = window.localStorage;
var map = L.map('map').setView([41, 21], 5);
var darkMap = L.tileLayer('https://tiles.stadiamaps.com/tiles/alidade_smooth_dark/{z}/{x}/{y}{r}.png', {
maxZoom: 20,
attribution: '© Stadia Maps, © OpenMapTiles © OpenStreetMap contributors'
}).addTo(map);
var marker1 = L.marker([40, 10]).addTo(map);
var marker2 = L.marker([40, 30]).addTo(map);
marker1.bindPopup('<div><input class="ipt" id="ipt1" /><button onclick="storeData(this);" class="save">SAVE</button></div>');
marker2.bindPopup('<div><input class="ipt" id="ipt2" /><button onclick="storeData(this);" class="save">SAVE</button></div>');
function storeData(btn) {
let ipt = btn.parentNode.querySelector('.ipt');
if (ipt.value != '') {
ls.setItem(ipt.id, ipt.value);
let str = 'Data stored in localStorage with key: ' + ipt.id + ', value: ' + ls.getItem(ipt.id);
alert(str);
} else {
console.log('Empty input!');
}
}
And a working fiddle (Please open in non-incognito).

Related

Leaflet map completely grey programmatically opening a popup tofa marker

I declare a leaflet map with
<div id="map" class="map-div"></div>
end initialize it with
var map = L.map('map').setView([51.178882, -1.826215],16);
$scope.map = map;
// OSM Mapnik
var osmUrl = "<a href='http://www.openstreetmap.org'>Open StreetMap</a>";
L.tileLayer(
'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© ' + osmUrl,
maxZoom: 18,
}).addTo(map);
I grab some data from my server, and and markers to the map, in a loop, by calling this function (it's AngularJS, but I doubt that that plays a role):
$scope.AddMarkerToMap = function(companyData, index, array)
{
var companyName = companyData.company_name;
var latitude = companyData.latitude;
var longitude = companyData.longitude;
var cssClassname = 'comapny_has_no_present_workers';
if (companyData['currentWorkers'] > 0)
cssClassname = 'comapny_has_present_workers';
var pubLatLng = L.latLng(latitude,longitude);
// see https://leafletjs.com/reference-1.4.0.html#marker
var marker = L.marker(pubLatLng,
{
// this is the tooltip hover stuff
title: companyData['currentWorkers'] + ' current matches ' + companyData['previousWorkers'] + ' previous matches',
// see https://leafletjs.com/reference-1.4.0.html#icon
// this is a permanent label.
icon: new L.DivIcon({
className: cssClassname,
////html: '<img class="my-div-image" src="http://png-3.vector.me/files/images/4/0/402272/aiga_air_transportation_bg_thumb"/>'+
//// '<span class="my-div-span">RAF Banff Airfield</span>'
html: '<span>' + companyName + '</span>'
})
}).addTo($scope.map);
// see https://leafletjs.com/reference-1.4.0.html#popup
marker.bindPopup("<b>Hello world!</b><br>I am a popup.").openPopup();
}; // AddMarkerToMap()
And the entire map is suddenly grey - with no problems reported in the developer console.
If I comment out the line
marker.bindPopup("<b>Hello world!</b><br>I am a popup.").openPopup();
then everything displays as expected.
The code seems correct, as per the Leaflet documentation.
[Updtae] I just checked and if I only marker.bindPopup("<b>Hello world!</b><br>I am a popup."), the the map displays and I can click on the marker to display the popup. But when I try to programmatically open it with .openPopup(); the map is all grey.
[Update++] the map and its markers display just fine, with any one of
marker.bindPopup("<b>Hello world!</b><br>I am a popup.");
$scope.map.fitBounds(bounds, {padding: [50, 50]});
but with both, the map is grey :-(
What am I doing wrongly?
I think the issue comes from trying to change the map view (possibly through openPopup with autoPan, which is on by default) too often, typically in a loop without giving any delay for the map to actually set the view between each call.
IIRC, this is already identified as a limitation in Leaflet, but I could not find the exact thread in the issue tracker unfortunately.
Normally, a very simple fix is simply to remove the map view changes within your loop, and keep only the very last one.
In your case, if you have the default behaviour of only 1 Popup being opened at a time, then that would definitely be a valid solution: just open the popup of your last Marker.
If you did configure your map to keep several Popups open simultaneously, and you do want to open all of them through your loop, then make sure to disable autoPan (at least during your loop).

How to update geojson markers periodically

What I am trying to do is to use Leaflet with OSM map,
and load data from PHP in GeoJSON format + update periodically.
I can manage to display a map, load data, but do not know how to update points instead of still adding a new ones.
function update_position() {
$.getJSON('link_to_php', function(data) {
//get data into object
var geojsonFeature = JSON.parse(data);
// how to remove here old markers???
//add new layer
var myLayer = L.geoJSON().addTo(mymap);
//add markers to layet
myLayer.addData(geojsonFeature);
setTimeout(update_position, 1000);
});
}
update_position();
have tried mymap.removeLayer("myLayer"); but this seems to now work inside of function. Please help
L.geoJSON extends from LayerGroup which provide a function named clearLayers(docs), so you call that to clear markers from the layer.
Also, it is recommended that you put the layer variable outside the function:
var geoJSONLayer = L.geoJSON().addTo(mymap);
function update_position() {
$.getJSON('link_to_php', function(data) {
//get data into object
var geojsonFeature = JSON.parse(data);
geoJSONLayer.clearLayers();
//add markers to layet
geoJSONLayer.addData(geojsonFeature);
setTimeout(update_position, 1000);
});
}
update_position();

marker with polyline while dragging the marker using leaflet

Hi I have connection between marker with polyline like this Image .
I am attaching a sample here.
How Can I make drag possible that when I drag the the marker with polyline.
example , If I drag the marker 3 it should also update the polyline point and where ever I put the marker 3 polyline should connect with marker 3.
I need this type of drag event that can update the polyline also when dragging the marker.
I am using leaflet for this purpose but still unable to solve the dragging logic of marker with polyline.
Here is the sample code I am using
$http.get("db/getConnectionData.php").then(function (response) {
$scope.links1 = response.data.records;
// $scope.showArrow();
angular.forEach($scope.links1, function(value, i) {
var source_panoId = $scope.links1[i].s_panoId;
var dest_panoId = $scope.links1[i].d_panoId;
var sPanoID = $scope.links1[i].sourcePano_id;
var dPpanoID = $scope.links1[i].destPano_id;
angular.forEach($scope.panoramas, function(value, index) {
if($scope.panoramas[index].panoId == source_panoId){
if($scope.links.indexOf($scope.panoramas[index])== -1){
$scope.links.push($scope.panoramas[index]);
}
var SlatLang = $scope.panoramas[index].project_latLng ;
var SLatLngArr = SlatLang.split(",");
var Slat = parseFloat(SLatLngArr[0]);
var Slang = parseFloat(SLatLngArr[1]);
var polypoint1 = [Slat, Slang];
angular.forEach($scope.panoramas, function(value, index1) {
if($scope.panoramas[index1].panoId == dest_panoId){
if($scope.links.indexOf($scope.panoramas[index1])== -1){
$scope.links.push($scope.panoramas[index1]);
}
var DlatLang = $scope.panoramas[index1].project_latLng ;
var DLatLngArr = DlatLang.split(",");
var Dlat = parseFloat(DLatLngArr[0]);
var Dlang = parseFloat(DLatLngArr[1]);
var polypoint2 = [Dlat, Dlang];
// Draw seperate polyline for each connection
polyline = L.polyline([[Slat, Slang],[Dlat, Dlang]],
{
color: 'blue',
weight: 5,
opacity: .7,
}
).addTo(map);
$scope.polycoords.push(polyline);
}
});
}
});
Here is the code that I am using to make drag of marker with polyline
angular.forEach($scope.panoramas, function(value, index4){
$scope.markers[index4].on('dragstart', function(e){
var latlngs = polyline.getLatLngs(),
latlng = $scope.markers[index4].getLatLng();
for (var i = 0; i < latlngs.length; i++) {
if (latlng.equals(latlngs[i])) {
this.polylineLatlng = i;
}
}
});//dragstart
$scope.markers[index4].on('drag', function(e){
var latlngs = polyline.getLatLngs(),
latlng = $scope.markers[index4].getLatLng();
latlngs.splice(this.polylineLatlng, 1, latlng);
polyline.setLatLngs(latlngs);
});//drag
$scope.markers[index4].on('dragend', function(e){
delete this.polylineLatlng;
});//dragEnd
});
First, when creating the marker, remember to pass the draggable option as true, like this:
var marker = L.marker(latLng, { draggable: true });
Now, check which drag event you want to attach a listener to and then call the redraw function of the polyline inside the callback, like this:
// var polyline defined somewhere
marker.on('drag', function (e) {
polyline.redraw();
});
If this doesn't work, please provide sample code so we can work around with it.
Edit
You also need to change the coordinates of the polyline, otherwise redraw will do nothing. Check out this answer on SO and see if it fits your needs.
Edit 2
You're using an array of polylines while the answer just uses one polyline which has the array of coordinates, so in your case you need to use two loops to accomplish the same task. You can make this faster and maybe use an object as a lookup table to get the right polyline for each marker, for example, like this:
var table = {};
// ...
table[marker] = polyline;
Then later you can get the polyline used for each marker. But anyway, here's what I think would work in your case the way it is in the sample (it was a little hard to understand but I hope it works for you).
I don't know where you are putting the second part of your sample (the event handlers) but I assume it's not inside the double loop that is creating the polylines, right? So this is what I came up with:
marker.on('dragstart', function (e) {
var markerLatLng = marker.getLatLng();
this.polylineLatLngs = [];
for (var i = 0; i < $scope.polycoords.length; i++) {
var polyline = $scope.polycoords[i];
var latLngs = polyline.getLatLngs()
for (var j = 0; j < latLngs.length; j++) {
if (markerLatLng.equals(latLngs[j])) {
this.polylineLatLngs.push([i, j]);
}
}
}
});
marker.on('drag', function (e) {
for (var i = 0; i < this.polylineLatLngs.length; i++) {
var polyline = $scope.polycoords[this.polylineLatLngs[i][0]];
var latLngs = polyline.getLatLngs();
var markerLatLng = marker.getLatLng();
latLngs.splice(this.polylineLatLngs[i][1], 1, markerLatLng);
polyline.setLatLngs(latLngs);
}
});
I am getting this type of behavior. Please let me know how I can solve this .
Thank you for your time.
This is the polyline created by getting data from db or by making the connection between panorama.
This Image when I start dragging the marker 2 I got the result like this
This image when I dragged the marker 3.
This type of result I am getting using the source code you provided above.

How do I get the latlng after the dragend event in leaflet?

I'm trying to update the lat/lng value of a marker after it is moved. The example provided uses a popup window to display the lat/lng.
I have a "dragend" event listener for the marker, but when I alert the value of e.latlng it returns undefined.
javascript:
function markerDrag(e){
alert("You dragged to: " + e.latlng);
}
function initialize() {
// Initialize the map
var map = L.map('map').setView([38.487, -75.641], 8);
L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: 'Map data © OpenStreetMap contributors, CC-BY-SA',
maxZoom: 18
}).addTo(map);
// Event Handlers
map.on('click', function(e){
var marker = new L.Marker(e.latlng, {draggable:true});
marker.bindPopup("<strong>"+e.latlng+"</strong>").addTo(map);
marker.on('dragend', markerDrag);
});
}
$(document).ready(initialize());
http://jsfiddle.net/rhewitt/Msrpq/4/
Use e.target.getLatLng() to get the latlng of the updated position.
// Script for adding marker on map click
function onMapClick(e) {
var marker = L.marker(e.latlng, {
draggable:true,
title:"Resource location",
alt:"Resource Location",
riseOnHover:true
}).addTo(map)
.bindPopup(e.latlng.toString()).openPopup();
// #12 : Update marker popup content on changing it's position
marker.on("dragend",function(e){
var chagedPos = e.target.getLatLng();
this.bindPopup(chagedPos.toString()).openPopup();
});
}
JSFiddle demo
latlng value is not in e.latlng but in e.target._latlng .
Use console.
While using e.target._latlng works (as proposed by this other answer), it's better practice to use
e.target.getLatLng();
That way we're not exposing any private variables, as is recommended by Leaflet:
Private properties and methods start with an underscore (_). This doesn’t make them private, just recommends developers not to use them directly.
I think the API changed.
Nowadays is: const { lat, lng } = e.target.getCenter();
if anyone is using react than you should use :
const map = useMap()
map.addEventListener("dragend" , ()=> {
const {lat , lng} = map.getCenter()
})

Json parse from Facebook events

I have had some trouble with fetching json from a groups events on facebook and then put them in a tableview to be used in a Appcelerator mobile app.
The idea is to have this as a calendar to show events for a club in a simple way.
I want to show the name of the event. The picture for that event and the date for the event.
All in a tablerow.
I have gotten to the part where i can get the Name and date for the events with this code:
Ti.UI.backgroundColor = '#dddddd';
var access_token='AAACEdEose0cBAAICGa4tFTcZAqCOGm2w9qPYGZBwNtJ1oZAcwaMAP2DDHZCN58cvVBZCHZADZAZBTPC8tTnpfQ7uGKI5j3SbMYcRmWquZCdPzhwZDZD';
var url = "https://graph.facebook.com/64306617564/events?&access_token=" + access_token ;
var win = Ti.UI.createWindow();
var table = Ti.UI.createTableView();
var tableData = [];
var json, data, row, name, start_time, id;
var xhr = Ti.Network.createHTTPClient({
onload: function() {
// Ti.API.debug(this.responseText);
json = JSON.parse(this.responseText);
for (i = 0; i < json.data.length; i++) {
data = json.data[i];
row = Ti.UI.createTableViewRow({
height:'60dp'
});
var name = Ti.UI.createLabel({
text:data.name,
font:{
fontSize:'18dp',
fontWeight:'bold'
},
height:'auto',
left:'50dp',
top:'5dp',
color:'#000',
touchEnabled:true
});
var start_time = Ti.UI.createLabel({
text:'"' + data.start_time + '"',
font:{
fontSize:'13dp'
},
height:'auto',
left:'15dp',
bottom:'5dp',
color:'#000',
touchEnabled:true
});
row.add(name);
row.add(start_time);
tableData.push(row);
}
table.setData(tableData);
},
onerror: function(e) {
Ti.API.debug("STATUS: " + this.status);
Ti.API.debug("TEXT: " + this.responseText);
Ti.API.debug("ERROR: " + e.error);
alert('There was an error retrieving the remote data. Try again.');
},
timeout:5000
});
xhr.open("GET", url);
xhr.send();
But when i want the specific event to open in a new window when clicked i just get the event that lies last on the screen when i put this in a browser:
https://graph.facebook.com/64306617564/events?&access_token=AAACEdEose0cBAOLAFWMKPmvgqEwap1ldnl7DeZBDKJC6YTZC4Goh6K5NHsvpOFmFQaGp1IekVsCxZCZCz3lwGpRcQG9ZBkcMrZAnLk4As8kgZDZD
And the access token expires REALLY fast. Any ideas how to make an access token that lasts longer?
Well, the code i am using to open the window is:
table.addEventListener('click',function(e) {
// Create the new window with the link from the post
var blogWindow = Ti.UI.createWindow({
title : data.name,
modal : true,
barColor: '#050505',
backgroundColor: '#050505'
});
var webView = Ti.UI.createWebView({url:'http://www.facebook.com/events/' + data.id});
blogWindow.add(webView);
// Create the close button to go in the left area of the navbar popup
var close = Titanium.UI.createButton({
title: 'Close',
style: Titanium.UI.iPhone.SystemButtonStyle.PLAIN
});
blogWindow.setLeftNavButton(close);
// Handle the close event
close.addEventListener('click',function() {
blogWindow.close();
});
blogWindow.open();
});
win.add(table);
win.open();
in my opinion that should open the event that is clicked on by parsing the ID from the row and putting it after the link.
Am i retarded or what is wrong?
It doesnt matter on which event i click it just open the last one all of the times.
And how can i get a thumbnail for the events?
Pls help........
When you click on table to get value from data which is not available.You can achieve it using you custom variable try to put this line of code at your row creation where you add your row in array i.e.row.data = data; and on table click event get that object using this alert(e.source.data); and check it. Best luck