Click link inside Leaflet Popup and do Javascript - javascript

I have a leaflet map up and running. It overlays a series of polygons (via GeoJSON) on the map and attaches popups to each polygon. Each of the popups display information about that polygon.
I'd like to have inside the popup a link that, when clicked, runs a javascript function that pulls further smaller polygons via AJAX and shows them.
I can't get the script to catch a click on the link via the normal jQuery/Javascript click events. Here's what I mean by normal (the following doesn't work):
$('a .smallPolygonLink').click(function(e){
console.log("One of the many Small Polygon Links was clicked");
});
The bindPopup part is as follows. It runs on each polygon when made and it pops up correctly on clicking on a polygon. It does show the link, just won't run the above code on click.
var popupContent = "Basic Information..." + '<a class="smallPolygonLink" href="#">Click here to see the smaller polygons</a>';
layer.bindPopup(popupContent);
Here's a JSFiddle illustrating the example, though in a far simpler form. http://jsfiddle.net/2XfVc/4/

The link element inside the popup is being dynamically generated from your markup each time the popup is opened. That means the link doesn't exist when you're trying to bind the handler to it.
The ideal approach here would be to use on to delegate event handling to the popup element or an ancestor of it. Unfortunately, the popup prevents event propagation, which is why delegating event handling to any static elements outside the popup won't work.
What you can do is preconstruct the link, attach the handler, and then pass it to the bindPopup method.
var link = $('TestLink').click(function() {
alert("test");
})[0];
marker.bindPopup(link);
Here is a demonstration: http://jsfiddle.net/2XfVc/7/
In general, to insert any sort of complex markup with multiple event handlers, use the folowing approach:
// Create an element to hold all your text and markup
var container = $('<div />');
// Delegate all event handling for the container itself and its contents to the container
container.on('click', '.smallPolygonLink', function() {
...
});
// Insert whatever you want into the container, using whichever approach you prefer
container.html("This is a link: <a href='#' class='smallPolygonLink'>Click me</a>.");
container.append($('<span class="bold">').text(" :)"))
// Insert the container into the popup
marker.bindPopup(container[0]);
Here is a demo: http://jsfiddle.net/8Lnt4/
See this Git issue for more on event propagation in leaflet popups.

While the Popup content wrapper prevents event propagation, events within the popup inner Markup propagate just fine. You can add events to popup elements when they are displayed on the map (and have become part of the DOM). Just watch for leaflet event popupopen.
var map = L.map('map').setView([51.505, 10], 7); //for example
//the .on() here is part of leaflet
map.on('popupopen', function() {
$('a .smallPolygonLink').click(function(e){
console.log("One of the many Small Polygon Links was clicked");
});
});
http://jsfiddle.net/tJGQ7/2/
This works like a charm for me. If your popup does not have a 'a .smallPolygonLink' the above code does nothing.
This code runs on every startup of a popup. However you don't have to worry that it attaches more than one handler to an element, since when the popup closes, the DOM nodes get thrown away.
There is a much more general way to do this. However, it involves eval(). Use at your own risk. But when AJAXloading partial pages that contain JS you run the same risks, so for your edification I present "executing JS inside your leaflet popups":
map.on('popupopen', function(){
var cont = document.getElementsByClassName('leaflet-popup-content')[0];
var lst = cont.getElementsByTagName('script');
for (var i=0; i<lst.length;i++) {
eval(lst[i].innerText)
}
});
demo: http://jsfiddle.net/tJGQ7/4/
Now you can write:
var popup_content = 'Testing the Link: TestLink<script> $(".speciallink").on("click", function(){alert("hello from inside the popup")});</script>';
marker.bindPopup(popup_content);

That's what I find on the mapbox offical website: Create a click event in a marker popup with Mapbox.js and jQuery. The comment explains why we say $('#map') instead of $('#mybutton').
var marker = L.marker([43.6475, -79.3838], {
icon: L.mapbox.marker.icon({
'marker-color': '#9c89cc'
})
})
.bindPopup('<button class="trigger">Say hi</button>')
.addTo(map);
//The HTML we put in bindPopup doesn't exist yet, so we can't just say
//$('#mybutton'). Instead, we listen for click events on the map element which will bubble up from the tooltip, once it's created and someone clicks on it.
$('#map').on('click', '.trigger', function() {
alert('Hello from Toronto!');});

I came across this problem, tried the solution above. But it didn't worked for me. Found the following pretty basic jquery solution.
// add your marker to the map
var my_marker = new L.marker([51.2323, 4.1231], {icon: my_icon});
var popup = L.popup().setContent('<a class="click" href="#">click</a>');
my_marker.addTo(map).bindPopup(popup);
// later on
jQuery("body").on('click','a.click', function(e){
e.preventDefault();
alert('clicked');
});

You can check inner properties of popup object, including _wrapper etc.
map.on('popupopen', _bindPopupClick);
map.on('popupclose', _unbindPopupClick);
var _bindPopupClick = function (e) {
if (e.popup) {
e.popup._wrapper.addEventListener('click', _bindPopupClickHandler);
}
};
var _unbindPopupClick = function (e) {
if (e.popup) {
e.popup._wrapper.removeEventListener('click', _bindPopupClickHandler);
}
}`

You can use jQuery to select the canvas element, but you'd have to use its own methods within the canvas. A decent start would be https://developer.mozilla.org/en/canvas_tutorial .

mapbox JavaScript library has an event:
bindPopup('<button class="trigger">Say hi</button>');
addTo(map);
$('#map').on('click', '.trigger', function() {
alert('Hello from Toronto!');
});
https://www.mapbox.com/mapbox.js/example/v1.0.0/clicks-in-popups/

Related

Selecting SVG items using D3 DataMaps?

I am looking at the Data Maps library of D3, and I would like to know how to go about manipulating the svg content. Let's say I look at the basic world map, how would I run a alert("Selected") by clicking on Canada? Or change its background color by clicking on it?
EDIT: In my specific instance, I am using the US map. I use the following lines to boot up the map:
var map = new Datamap({element: document.getElementById('maincontains'),
scope: 'usa',
fills: {defaultFill: 'rgb(217, 217, 217)'}
});
Now, in the usa.js I find IDs such as "NY". However, this does not allow me to
document.getElementById("NY").addEventListener('click', function(){
alert("New York");}
The documentation on Events says the following:
All events are bubbled up to the root svg element and to listen to
events, use the done callback.
So in order to bind a click event and alert the name, use the done event of the map object and use the svg object inside the event handler:
<script>
var map = new Datamap({
element: document.getElementById('container'),
done: function(datamap) {
datamap.svg.selectAll('.datamaps-subunit').on('click', function(geography) {
alert(geography.properties.name);
});
}
});
</script>
My example click on Greenland:
Further restrictions (e.g. only specific countries) could be made using the properties.

How is it possible that the jQuery works on Chrome console, but does not itself?

I would like to make a overlay when the uses make hover event on a link.
This part ok, the overlay created and everything fine.
But I also would like to remove this overlay, when user click (or hover) for it, and this part create a strange bug.
I try clicking for the overlay and its dosen't close, nothing happening, but if you paste script to the chrome console, this working fine.
Js, first part, add script:
var overlay = jQuery('<div class="overlay"> </div>');
$("#link-'.$myqlVideoID.'").hover(function() {
$("#hover-").attr("src","http://youtube.com/embed/'.$myqlVideoID.'?autoplay=1");
$(".drop-target").css("background-color","#070707");
$(".drop-target").css("padding","11px");
$(".drop-target").css("margin-bottom","16px");
$(".drop-target").show().fadeIn("3000");
overlay.appendTo(document.body)
});
And the second part, remove overlay:
$(document).ready(function() {
$(".overlay").click(function() {
$("#hover-").removeAttr("src");
$(".drop-target").hide().fadeOut("3000");
$(".overlay").remove();
console.log("clicked");
});
});
My site is where you can see the bug:
http://neocsatblog.mblx.hu/search/
Just search something and scroll down to "Cimkék"
Try delegating the event on the overlay by writing the following:
$(document).on('click', '.overlay', function () {
//The rest of your code
}) ;
And same for the rest of your event handlers.
The reason for this is that the element overlay is being added dynamically, and the script doesn't know about it at the moment when it's being instantiated.

Jquery Selector fails after setContent called on info window

I have a google maps info window that I open on a map, directly after which I want to bind event listeners to parts of the html in the info window. I do this with JQuery. The code goes something like:
myInfoWindow.open(map);
$('#someIdInInfoWindow').bind({
click: function() { foo1(); },
mouseenter: function() { foo2(); }
});
Unfortunately, I think Google makes most of their libraries asynchronous, so the content of the info window is not actually set until after the JQuery selector has been called.
How can I fix this so the event handlers are properly set? Thanks!
You must wait for the domready-event of the infoWindow before you add the listeners, at this time the HTML-element representing the infowindow has been attached to the document and it's contents are accessible :
google.maps.event.addListener(myInfoWindow,'domready',function(){
$('#someIdInInfoWindow').bind({
click: function() { foo1(); },
mouseenter: function() { foo2(); }
});
});
This applies when the content of the infoWindow is set via a string, when you assign it via a node you may also add the listeners directly to the particular element when you create it:
var content = $('<div/>')
.append($('<div/>',{id:'someIdInInfoWindow'})
.text('some text')
.click(foo1)
.mouseenter(foo2));
myInfoWindow.setContent(content[0]);
myInfoWindow.open(map);

jsPlumb: Can't click() on a div inside a div that acts as a jsPlumb source/target

I'm using jsPlumb. My current functionality lets me create a .project div that can then have .task divs inside it. The .project div has 3 clickable buttons which all work using jQuery and the .tasks inside the .project have a single close button which also works.
As can we seen here: http://jsfiddle.net/9yej6/3/
(click the add project button then click on the green project and try to click on the X near some task - an alert should pop up)
However, whenever I try to make the .tasks a makeTarget/makeSource using jsPlumb it surpasses (probably not the best word) any other event done by jQuery. That is when I click on the X icon of the .task it instead acts as if I click on the .task itself and tries to create jsPlumb's bond.
As can be seen here: http://jsfiddle.net/9yej6/4/
So the following line no longer works (note I'm using the on() function since the .project/.task divs are dynamically created):
$("#container").on('click','.task .close',function(e) {
alert('a task`s add was clicked');
});
Initially the addTask() function was (which worked, but you can't add jsPlumb bonds):
function addTask(parentId, index) {
var newState = $('<div>').attr('id', 'state' + index).addClass('task');
var close = $('<div>').addClass('close');
newState.append(close);
var title = $('<div>').addClass('title').text('task ' + index);;
newState.append(title);
$(parentId).append(newState);
}
But when I add the makeTarget()/makeSource() calls to it, it seems to surpass any other jQuery event handling. Where my new addTask() function becomes:
function addTask(parentId, index) {
var newState = $('<div>').attr('id', 'state' + index).addClass('task');
var close = $('<div>').addClass('close');
newState.append(close);
var title = $('<div>').addClass('title').text('task ' + index);;
newState.append(title);
$(parentId).append(newState);
jsPlumb.makeTarget(newState, {
anchor: 'Continuous'
});
jsPlumb.makeSource(newState, {
anchor: 'Continuous'
});
}
You can also use the filter parameter to specify what element to be included for the object drag.
See my complete answer here.
http://jsplumbtoolkit.com/doc/connections.html#sourcefilter
jsPlumb.makeSource("foo", {
filter:":not(a)"
});
Above means, don't interfere with operations related to a (anchor tag).
As mentioned,
$("#container").on('click','.task .close',function(e) {
alert('a task`s add was clicked');
});
This code doesn't work becasue you have made the '.task' element as either target or source part of jsPlumb hence the mouse events will be handled by jsPlumb which prevents the default event handling(jQuery or pure JS) of those elements.
In such case you need to create a small rectangle DIV(refer image) from where the user can drag the connection instead of an entire DIV.

Jquery on mousedown not working on dynamically generated elements

So i'm trying to create a js/css "wave game" like tower defense ones.
When all the pre-generated enemys from first wave are dead, it spawns the second wave and so on.
So far so good.
The problem is that i just can't attack mobs dynamically spawned within second wave.
I used to try .live() in similar cases, but its deprecated, so i'm trying .on(), as instructed
$('.enemy').on('mousedown' , function(event) {
//attack code
}
Its working fine for initial mobs (1st wave) but it still just not working on dynamic mobs (>= 2nd wave)
Help, guys, please?
You need to specify an element that is already there when the DOM is created. In the parameters, you specify the elements you want to add the mousedown method. By simply assigning $('.enemy'), it will attach the method to those that are already present in the DOM.
$('body').on('mousedown', '.enemy', function(event) {
//attack code
}
As Wex mentioned in the comments, instead of writting $('body') you should use the container's name (the container which wraps the .enemy elements. This way, when a .enemy element is added, the event doesn't need to bubble all the way up to the body tag.
The binding '.on()' works only with the content that created earlier then the script ran.
So one solution could be you bind the event to the parent element.
$('.PARENT_ELEMENT').on('mousedown', '.enemy', function(event){
// your code here
}
That should do it.
I made this google like drop down suggestions search box and I faced a problem similar to yours where there was suggestions disappearing before the re-direct happened. I overcame it by using and modifing vyx.ca answer:
var mousedownHappened = false;
var clicked_link;
$("#search-box").blur(function(e) {
if (mousedownHappened)// cancel the blur event
{
mousedownHappened = false;
window.location.href = clicked_link;
} else {
// no link was clicked just remove the suggestions box if exists
if ($('#search-btn').next().hasClass('suggestions')) {
$(".suggestions").remove();
}
}
});
//attaching the event to the document is better
$(document).on('mousedown', '.suggestions a', function() {
clicked_link= $(this).attr('href');
mousedownHappened = true;
});

Categories

Resources