Mapbox GL Popup .setDOMContent example - dom

I'm trying to create a customized button to appear on a pop up which generates a dynamic link (a URL). I don't seem to be able to do this via the .setHTML because of the timing, can't bind a button to a function at runtime. So I thought I'd try the newish .setDOMContent
There's zero information online as to how this feature works. I'm wondering if anyone has an example of this where a button is added to the popup that can run a function and send data.
Here's my very poor attempt at setting this up.
This function creates the popup
function GameObjectPopup(myObject) {
var features = map.queryRenderedFeatures(myObject.point, {
layers: ['seed']
});
if (!features.length) {
return;
}
var feature = features[0];
// Populate the popup and set its coordinates
// based on the feature found.
var popup = new mapboxgl.Popup()
.setLngLat(feature.geometry.coordinates)
.setHTML(ClickedGameObject(feature))
.setDOMContent(ClickedGameObject2(feature))
.addTo(map);
};
This function adds the html via the .setHTML
function ClickedGameObject(feature){
console.log("clicked on button");
var html = '';
html += "<div id='mapboxgl-popup'>";
html += "<h2>" + feature.properties.title + "</h2>";
html += "<p>" + feature.properties.description + "</p>";
html += "<button class='content' id='btn-collectobj' value='Collect'>";
html += "</div>";
return html;
}
This function wants to add the DOM content via the .setDOMContent
function ClickedGameObject2(feature){
document.getElementById('btn-collectobj').addEventListener('click', function()
{
console.log("clicked a button");
AddGameObjectToInventory(feature.geometry.coordinates);
});
}
I'm trying to pipe the variable from features.geometry.coordinates into the function AddGameObjectToInventory()
the error I'm getting when clicking on an object (so as popup is being generated)
Uncaught TypeError: Cannot read property 'addEventListener' of null

Popup#setHTML takes a string that represents some HTML content:
var str = "<h1>Hello, World!</h1>"
popup.setHTML(str);
while Popup#setDOMContent takes actual HTML nodes. i.e:
var h1 = document.createElement('h1');
h1.innerHTML="Hello, World";
popup.setDOMContent(h1);
both of those code snippets would result in identical Popup HTML contents. You wouldn't want to use both methods on a single popup because they are two different ways to do the same thing.
The problem in the code you shared is that you're trying to use the setDOMContent to add an event listener to your button, but you don't need to access the Popup object to add the event listener once the popup DOM content has been added to the map. Here is a working version of what I think you're trying to do: https://jsfiddle.net/h4j554sk/

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.

Mouse over popup on leaflet.js marker

How can I add a mouse over pop up on leaflet.js marker . the pop up data will be dynamic.
I have a service which returns a lat & lon positions which will mark on a map.
I would require a popup on mouse over a marker . the event should send the lat and long position for ex to : http://api.openweathermap.org/data/2.5/weather?lat=40&lon=-100
the data from service should be in popup content.
I have tried but cant build the pop up content dynamically each marker
Please do the needful.
below is the code i have used for markers statesdata is array which stores the lat and longitude values
for ( var i=0; i < totalLength1; i++ ) {
var LamMarker = new L.marker([statesData1[i].KK, statesData1[i].LL]).on('contextmenu',function(e) {
onClick(this, i);
}).on('click',function(e) {
onClick1(this, i)
});
marker_a1.push(LamMarker);
map.addLayer(marker_a1[i]);
on click we call click1 function on context of marker we call click function
How can i add a pop on mouse over passing lat and long from the above code?
Attaching a popup to a marker is fairly easy. It is done by calling the bindPopup method of your L.Marker instance. Per default a popup opens on the click event of the L.Marker instance and closes on the click event of your L.Map instance. Now if you want to do something when a popup opens you can listen to the popupopen event of your L.Map instance.
When you want fetch external data in the background on the popupopen event that is usually done via XHR/AJAX. You can write your own logic or use something like jQuery's XHR/AJAX methods like $.getJSON. Once you receive response data you can then update your popup's content.
In code with comments to explain further:
// A new marker
var marker = new L.Marker([40.7127, -74.0059]).addTo(map);
// Bind popup with content
marker.bindPopup('No data yet, please wait...');
// Listen for the popupopen event on the map
map.on('popupopen', function(event){
// Grab the latitude and longitude from the popup
var ll = event.popup.getLatLng();
// Create url to use for getting the data
var url = 'http://api.openweathermap.org/data/2.5/weather?lat='+ll.lat+'&lon='+ll.lng;
// Fetch the data with the created url
$.getJSON(url, function(response){
// Use response data to update the popup's content
event.popup.setContent('Temperature: ' + response.main.temp);
});
});
// Listen for the popupclose event on the map
map.on('popupclose', function(event){
// Restore previous content
event.popup.setContent('No data yet, please wait...');
});
Here's a working example on Plunker: http://plnkr.co/edit/oq7RO5?p=preview
After comments:
If you want to open the popup on hover instead of click you can add this:
marker.on('mouseover', function(event){
marker.openPopup();
});
If you want to close the popup when you stop hovering instead of map click add this:
marker.on('mouseout', function(event){
marker.closePopup();
});
Here's an updated example: http://plnkr.co/edit/wlPV4F?p=preview
I got fed up with fighting with leaflet's built in functionality. The first thing I did was use the alt option to assign a key to the marker:
var myLocation = myMap.addLayer(L.marker(lat,lng],{icon: icon,alt: myKey}))
The next thing was assign an id using this alt and a title via jQuery (why you can't do that by default irritates me):
$('img[alt='+myKey+']').attr('id','marker_'+myKey).attr('title',sRolloverContent)
Then, I used jQuery tooltip (html will only render this way):
$('#marker_'+myKey).tooltip({
content: sRolloverContent
})
Also, by using the jQuery tooltip instead of the click-only bindPopup, I am able to fire the tooltip from my list, where the row has a matching key id:
$('.search-result-list').live('mouseover',function(){
$('#marker_'+$(this).attr('id')).tooltip('open')
})
$('.search-result-list').live('mouseout',function(){
$('#marker_'+$(this).attr('id')).tooltip('close')
})
By adding the id, I can easily use jQuery to do whatever I want, like highlight a list of locations when the marker is hovered:
$('#marker_'+iFireRescue_id).on('mouseover',function(){
('tr#'+getIndex($(this).attr('id'))).removeClass('alt').removeClass('alt-not').addClass('highlight')
})
$('#marker_'+myKey).on('mouseout',function(){
$('tr#'+getIndex($(this).attr('id'))).removeClass('highlight')
$('#search-results-table tbody tr:odd').addClass('alt')
$('#search-results-table tbody tr:even').addClass('alt-not')
})

Issue with document.ready function in jQuery

I am having one issue with document.ready jQuery function.
On load the document.ready function is working fine. When I click on the button or href link, I want to reconnect with the document.ready function where I have set of code in JavaScript file.
Here is the actual scenario. Please find below sample JS code:
$(document).ready(function() {
var title = "This is your title";
var shortText = jQuery.trim(title).substring(0, 10).split(" ").slice(0, -1).join(" ") + "...";
alert(shortText );
});
After clicking submit button i am adding the input fields data in the below table row. In which description texts are also added in one of table row columns. If description field has more than 100 character, I am pushing the above mentioned JavaScript code from external .JS file. How can i refresh the Java script function without refreshing the page? Anyone have idea?
Please share your opinion.
Create a function, that you can call both in document.ready, and also anywhere else, such as a buttons click event:
function myfunc(){
var title = "This is your title";
var shortText = jQuery.trim(title).substring(0, 10).split(" ").slice(0, -1).join(" ") + "...";
alert(shortText );
}
$(document).ready(function() {
//call when document is ready
myfunc();
//call again when button is clicked
$('#button').click(myfunc());
});

jQuery - Refresh Contents of a DIV

I have a form in a jQuery popup on a webpage. The jQuery popup is a div named .vote-form and the form inside it has the name "#form".
When the form is submitted, the content inside the jQuery popup changes to a success message. I need to make it so that when the jQuery popup is closed, the success message is removed and the form is refreshed back to the original form, so that when the jQuery popup is opened again, the form is showing again and NOT the success message.
My feeble attempt to get this result involved refreshing the ENTIRE page when the jQuery popup is closed. This PARTLY has the desired result, but when the page is refreshed, most browsers get a popup asking if the user wants to resubmit the form content. I need to avoid this.
This was my code handling the closing of the .vote-form:
$('.vote-form-close').click(function(event) {
event.stopPropagation();
$(".vote-form").fadeOut("normal");
$("#the-lights").fadeTo("slow",0);
$("#the-lights").css({'display' : 'none'});
window.location.reload();
});
I suspect that its possible to refresh ONLY the div, and not the entire page, but I do not know how to accomplish it.
Can someone assist me?
EDIT: Based on one of the answers below, I modified my code. I also wanted to show the code used to open the form up too:
$('.vote').click(function() {
$(this).parent().find(".vote-form").fadeIn("normal");
$("#the-lights").css({'display' : 'block'});
$("#the-lights").fadeTo("slow",0.7);
});
$('.vote-form-close').click(function(event) {
event.stopPropagation();
$(".vote-form").fadeOut("normal");
$("#the-lights").fadeTo("slow",0);
$("#the-lights").css({'display' : 'none'});
$(".vote-form").load(window.location.href + " .vote-form-container");
});
Here is the problem - I have 3 forms on the page. When "vote-form-container" is loaded, its loading ALL THREE forms into the .vote-form box - how do I modify the code to only load the .vote-form-container that is part of the specific .vote-form - I suspect I have to use $(this) but I tried modifying the code to this and it didnt work:
$(".vote-form")(this).load(window.location.href + " .vote-form-container");
I am thinking I did it wrong.
EDIT 2: Now the "Close" button dosen't work after the form is reloaded the first time:
$('.vote').click(function() {
$(this).parent().find(".vote-form").fadeIn("normal");
$("#the-lights").css({'display' : 'block'});
$("#the-lights").fadeTo("slow",0.7);
});
$('.vote-form-close').click(function(event) {
event.stopPropagation();
$(".vote-form").fadeOut("normal");
$("#the-lights").fadeTo("slow",0);
$("#the-lights").css({'display' : 'none'});
var current_form = $(this).closest('.vote-form'),
index = $('.vote-form').index(current_form)
current_form.load(window.location.href + " .vote-form-container:eq(" + index + ")");
});
Don't reload the page but redirect your user:
window.location.href = window.location.href.toString()
Or load the new form with ajax:
$(".vote-form").load(window.location.href + " .vote-form");
For more information on the ajax approach see api.jquery.com/load/#loading-page-fragments
Update:
Using jQuery the index function you are able to replace only the current form.
// I asume your button is in the form
var current_form = $(this).closest('.vote-form'),
index = $('.vote-form').index(current_form)
current_form.load(window.location.href + " .vote-form:eq(" + index + ")");
... I need to make it so that when the jQuery popup is closed, the success message is removed and the form is refreshed back to the original form...
So, if I well understood:
$('.vote-form-close').click(function(event) {
event.stopPropagation();
var vf = $(".vote-form");
/* fadeout and remove inner content of the popup */
vf.fadeOut("normal", function() { vf.empty(); });
/* reset the form */
document.getElementById('form').reset();
...
});

Jquery in Custom HTML Helper Extensions to pick value from the form

I have used this custom Helper in My Razor View.
#Html.Link("OpenewWindow", Constants.Value, new { k = Constants.k, Staff_ID = LoginHelper.GetLoggedInUser() }, new { id = "mytag", target="_blank" })
When I Click on this link it opens me a new window with the Querystrings ConstantValue/Constants?=someValue&Staff_ID=UserLoggedName.
I want to pick the radio button selected value on the form and pass the checked value in QueryString.
So where can I use Jquery function in my custom Helper method to pick the value from the form.
The Custom Helper method takes this kind of aurguments.
public static IHtmlString Link(this HtmlHelper htmlHelper, string linkText, string baseUrl, object query, object htmlAttributes).
You could use javascript to do that. For example you could subscribe to the click event of the link and then open a popup window by appending the new query string parameter:
$(function() {
$('#id_of_link').click(function() {
var url = this.href;
if (url.indexOf('?') > -1) {
url += '&';
} else {
url += '?';
}
// get the value of the radio button
var value = $(':radio[name="name_of_your_radio_groups"]:checked').val();
url += url + 'radiovalue=' + encodeURIComponent(value);
window.open(url, 'newwindow');
// cancel the default action
return false;
});
});
If you don't need to use javascript then a cleaner approach is to use a form instead of a link. This way the value of the selected radio button will automatically be sent.