Leaflet-geoman remove button not working after bind a new layer click function - leaflet

I need to bind a custom click function on the drawn shapes. I'm using the following code for that:
map.on('pm:create', function(e) {
e.layer.on('click', function(e) {
document.getElementById('info-pane').style.display = 'block';
});
});
When I bind this new click function, I'm not able to remove the shape anymore. When I am in the remove mode, the click is triggering the show info-pane instead of remove the shape.
How can I bind a custom click function to the shapes without "deactivate" any leaflet-geoman functionality such as the Remove ?

Well,
Including this L.DomEvent.stopPropagation(e); seems to be working now.
map.on('pm:create', function(e) {
e.layer.on('click', function(e) {
document.getElementById('info-pane').style.display = 'block';
});
L.DomEvent.stopPropagation(e);
});

Related

Leaflet - How to add click event to button inside marker pop up in ionic app?

I am trying to add a click listener to a button in a leaftlet popup in my ionic app.
Here I am creating the map & displaying markers, also the method I want called when the header tag is clicked is also below:
makeCapitalMarkers(map: L.map): void {
let eventHandlerAssigned = false;
this.http.get(this.capitals).subscribe((res: any) => {
for (const c of res.features) {
const lat = c.geometry.coordinates[0];
const lon = c.geometry.coordinates[1];
let marker = L.marker([lon, lat]).bindPopup(`
<h4 class="link">Click me!</h4>
`);
marker.addTo(map);
}
});
map.on('popupopen', function () {
console.log('Popup Open')
if (!eventHandlerAssigned && document.querySelector('.link')) {
console.log('Inside if')
const link = document.querySelector('.link')
link.addEventListener('click', this.buttonClicked())
eventHandlerAssigned = true
}
})
}
buttonClicked(event) {
console.log('EXECUTED');
}
When I click this header, Popup Open & Inside if are printed in the console, so I know I'm getting inside the If statement, but for some reason the buttonClicked() function isn't being executed.
Can someone please tell me why this is the current behaviour?
I just ran into this issue like 2 hours ago. I'm not familiar with ionic, but hopefully this will help.
Create a variable that keeps track of whether or not the content of your popup has an event handler attached to it already. Then you can add an event listener to the map to listen for a popup to open with map.on('popupopen', function(){}). When that happens, the DOM content in the popup is rendered and available to grab with a querySelector or getElementById. So you can target that, and add an event listener to it. You'll have to also create an event for map.on('popupclose', () => {}), and inside that, remove the event listener from the dom node that you had attached it to.
You'd need to do this for every unique popup you create whose content you want to add an event listener to. But perhaps you can build a function that will do that for you. Here's an example:
const someMarker = L.marker(map.getCenter()).bindPopup(`
<h4 class="norwayLink">To Norway!</h4>
`)
someMarker.addTo(map)
function flyToNorway(){
map.flyTo([
47.57652571374621,
-27.333984375
],3,{animate: true, duration: 5})
someMarker.closePopup()
}
let eventHandlerAssigned = false
map.on('popupopen', function(){
if (!eventHandlerAssigned && document.querySelector('.norwayLink')){
const link = document.querySelector('.norwayLink')
link.addEventListener('click', flyToNorway)
eventHandlerAssigned = true
}
})
map.on('popupclose', function(){
document.querySelector('.norwayLink').removeEventListener('click', flyToNorway)
eventHandlerAssigned = false
})
This is how I targeted the popup content and added a link to it in the demo for my plugin.
So yes you can't do (click) event binding by just adding static HTML. One way to achieve what you want can be by adding listeners after this new dom element is added, see pseudo-code below:
makeCapitalMarkers(map: L.map): void {
marker.bindPopup(this.popUpService.makeCapitalPopup(c));
marker.addTo(map);
addListener();
}
makeCapitalPopup(data: any): string {
return `` +
`<div>Name: John</div>` +
`<div>Address: 5 ....</div>` +
`<br/><button id="myButton" type="button" class="btn btn-primary" >Click me!</button>`
}
addListener() {
document.getElementById('myButton').addEventListener('click', onClickMethod
}
Ideally with Angular, we should not directly be working with DOM, so if this approach above works you can refactor adding event listener via Renderer.
Also I am not familiar with Leaflet library - but for the above approach to work you need to account for any async methods (if any), so that you were calling getElementById only after such DOM element was successfully added to the DOM.

Double on click event with mapbox gl

I am redrawing layers on style.load event and removing the layers
map.on('style.load', function() {
loadByBounds(tempBounds)
});
function loadByBounds(b) {
if (map.getLayer("cluster-count")) {
map.removeLayer("cluster-count");
}
...
map.on('click', 'unclustered-point', function(e) {
var popup = new mapboxgl.Popup()
.setLngLat(e.features[0].geometry.coordinates)
.setHTML(text)
.addTo(map);
})}
But how to remove map.on('click') events? As when I click the point the Popup() displays 2 times. And when I change layer one more time the onclick event fires 3 times and so on. So I think I have to remove the click event but how? Thanks
You might wanna use map.once(). This will add a listener that will be called only once to a specified event type. However after 1 click event got fired this event listener won't listen to any further click events.
https://www.mapbox.com/mapbox-gl-js/api/#evented#once
With map.off() it's basically the opposite of map.on() and you can use it to unregister any applied event listeners. However you would need to add event listeners without an anonymous function in order to use map.off().
https://www.mapbox.com/mapbox-gl-js/api/#map#off
// you would need to use a named function
function clickHandler(e) {
// handle click
}
map.on('click', clickHandler);
// then you can use
map.off('click', clickHandler);
// With an anonymous function you won't be able to use map.off
map.on('click', (e) => {
// handle click
});
To prevent your app from registering multiple listeners you maybe need to set a flag that gets set after your first event listener got applied.
let notListening = true;
function loadByBounds(b) {
// ....
if (notListening) {
notListening = false;
map.on('click', (e) => {
// do something
});
}
}

Leaflet popupclose event fires whilst dragging marker

In my app I add a temporary dragable marker to a map and open its popup. I found that when the marker is dragged the popup closes. To get around this I added the code as per Force Leaflet popup to stay open when a draggable marker is moved
var marker = new L.Marker([setLat, setLng], {icon:questionIcon, draggable:true});
marker.bindPopup("popup content").addTo(map).openPopup();
marker.on('dragend', function(e) {
marker.openPopup();
});
However, I also want to make sure that if the user closes the popup manually (using the standard 'x' top-right) that the temporary marker is removed from the map. So I added ...
marker.on('popupclose', function(e) {
map.removeLayer(marker);
});
... but, this also fires when dragging the marker. So as soon as the user tries to reposition the marker by dragging it, it completely disappears.
Is there a way to distinguish between the two events so I can handle them differently? Or back to the original question, disable the popupclose from happening when the marker is dragged?
I met the same issue ,
and I solved it by doing this inorder to distinguish between the two events :
marker._popup._closeButton.onclick = function( ){
console.log("click closed ");
map.removeLayer(marker);
}
http://jsfiddle.net/Zoubir/v71Lhn5s/
I met the similar issue. Here's my solution
var IsDragging = false;
marker.on('dragstart', function (event) {
IsDragging = true;
});
marker.on('dragend', function (event) {
marker.openPopup();
IsDragging = false;
});
map.on('popupclose', function(e) {
setTimeout(function(){
if(LS.Send.IsDragging == false){
map.removeLayer(LS.Send.Marker);
}
},300);
});

SAPUI5 mixing mobile (sap.m) and desktop (sap.ui.commons)

I am working on a desktop SAPUI5 application and need to use TileContainer/Tiles in one of the page but noticed that press event is not working for this. Tried other mobile controls e.g. sap.m.Button press events but they are also not working.
Any idea?
Mobile controls will be work fine with touch events only. You need to set onclick events. You have 3 options to do this:
1) Attach onclick to target control:
var oButton = new sap.m.Button({
text : "Hello",
press : function() { alert('You've pressed me!') }
}).attachBrowserEvent('click',
function(event){
sap.ui.getCore().byId(event.target.id).firePress()
});
2) Extend standart mobile controls:
sap.m.Button.extend('my.Button');
my.Button.prototype.onclick = function(){
this.ontap.apply(this, arguments);
};
my.Button.prototype.onmousedown = function(){
this.ontouchstart.apply(this, arguments);
};
my.Button.prototype.onmousemove = function(){
this.ontouchmove.apply(this, arguments);
};
my.Button.prototype.onmouseup = function(){
this.ontouchend.apply(this, arguments);
};
3) Modify standart controls(not really good idea):
sap.m.Button.prototype.onclick = function(){
this.ontap.apply(this, arguments);
};
...
I was not adding sap.m in sap-ui-bootstrap, adding this made moible ui controls working.
data-sap-ui-libs="sap.ui.commons, sap.m"
thanks any way qmacro and Nikolay...

Twitter Bootstrap Modal Form: How to drag and drop?

I would like to be able to move around (on the greyed-out background, by dragging and dropping) the modal form that is provided by Bootstrap 2. Can anyone tell me what the best practice for achieving this is?
The bootstrap doesn't come with any dragging and dropping functionality by default, but you can add a little jQuery UI spice into the mix to get the effect you're looking for. For example, using the draggable interaction from the framework you can target your modal ID to allow it to be dragged around within the modal backdrop.
Try this:
JS
$("#myModal").draggable({
handle: ".modal-header"
});
Demo, edit here.
Update: bootstrap3 demo
Whatever draggable option you go for, you might want to turn off the *-transition properties for .modal.fade in bootstrap’s CSS file, or at least write some JS that temporarily disables them during dragging. Otherwise, the modal doesn’t drag exactly as you would expect.
You can use a little script likes this.
simplified from Draggable without jQuery UI
(function ($) {
$.fn.drags = function (opt) {
opt = $.extend({
handle: "",
cursor: "move"
}, opt);
var $selected = this;
var $elements = (opt.handle === "") ? this : this.find(opt.handle);
$elements.css('cursor', opt.cursor).on("mousedown", function (e) {
var pos_y = $selected.offset().top - e.pageY,
pos_x = $selected.offset().left - e.pageX;
$(document).on("mousemove", function (e) {
$selected.offset({
top: e.pageY + pos_y,
left: e.pageX + pos_x
});
}).on("mouseup", function () {
$(this).off("mousemove"); // Unbind events from document
});
e.preventDefault(); // disable selection
});
return this;
};
})(jQuery);
example : $("#someDlg").modal().drags({handle:".modal-header"});
Building on previous answers utilizing jQuery UI, this, included once, will apply to all your modals and keep the modal on screen, so users don't accidentally move the header off screen so they can no longer access the handle. Also sets the cursor to 'move' for better discoverability.
$(document).on('shown.bs.modal', function(evt) {
let $modal = $(evt.target);
$modal.find('.modal-content').draggable({
handle: ".modal-header",
containment: $modal
});
$modal.find('.modal-header').css('cursor', 'move')
});
evt.target is the .modal which is the translucent overlay behind the actual .modal-content.
jquery UI is large and can conflict with bootstrap.
An alternative is DragDrop.js: http://kbjr.github.io/DragDrop/index.html
DragDrop.bind($('#myModal')[0], {
anchor: $('#myModal .modal-header')
});
You still have to deal with transitions, as #user535673 suggests. I just remove the fade class from my dialog.