Concatenate HTML element with HTML string for Leaflet's bindPopup - javascript

I am trying to write a functionality for editing feature attributes through layer.bindPopup for Leaflet features. At this point I have pretty much everything I need, except of the one last thing: Documentation is saying that layer.bindPopup takes either HTML string or HTML element, so I need to concatenate my HTMLString with two elements: saveChanges button and speed_input input and then feed layer.bindPopup with it. Any manipulations with $.append did not help. Any suggestions on how to resolve this?
function onEachArc(feature, layer) {
// Create an input
var speed_input = L.DomUtil.create('input', 'speed');
// Set a feature property as value
speed_input.value = feature.properties.speed;
// Add a listener to watch for change on time input
L.DomEvent.addListener(speed_input, 'change', function(){
// Change the value of speed
feature.properties.speed = speed_input.value;
});
// Bind popup to layer with input
HTMLString = '<table style="width:100%">\
<tr style="background-color:grey">\
<th><b>Arc Numer: </b>' + feature.properties.linkstr + '</br></th>\
</tr>\
<tr>\
<td><b>Speed: </b> ' + feature.properties.speed + '.</div></td>\
</tr>\
</table>';
var saveChanges = document.createElement('button');
saveChanges.innerHTML = 'Save Changes';
saveChanges.onclick = function(){
$.ajax({
type:"POST",
url:"php/updateFeature.php",
data: {feature: feature},
success: function(data){
$('#test').html(data);
}
});
//return false;
}
};
/*
This did not help
var box = document.createElement("div");
box.style.width = "100px";
box.style.height = "100px";
$("#box").append("#saveChanges");
layer.bindPopup(box);
*/
layer.bindPopup(saveChanges);
};

You could use innerHTML:
The Element.innerHTML property sets or gets the HTML syntax describing the element's descendants.
var form = L.DomUtil.create('form', 'my-form');
form.innerHTML = '<input type="text" class="my-input" />';
var button = L.DomUtil.create('button', 'my-button', form);
button.textContent = 'Ok!';
http://plnkr.co/edit/DiK1zj?p=info
or use outerHTML:
On return, content contains the serialized HTML fragment describing the element and its descendants.
var inputHTML = '<input type="text" class="my-input" />';
var button = L.DomUtil.create('button', 'my-button', form);
button.textContent = 'Ok!';
var buttonHTML = button.outerHTML;
var form = '<form class="my-form">' + inputHTML + buttonHTML + '</form>';
http://plnkr.co/edit/Z6rADJ?p=preview
That said (and after reading your comment), i must say: this works but is very hacky. I wouldn't recommend doing this sort of thing this way. You either build your form with HTML elements or use a template/string and convert that into HTML elements so you can attach handlers and process stuff. Mixing things up will get you into trouble. I would approach it this way:
The template:
var template = '<form id="popup-form">\
<label for="input-speed">New speed:</label>\
<input id="input-speed" class="popup-input" type="number" />\
<table class="popup-table">\
<tr class="popup-table-row">\
<th class="popup-table-header">Arc numer:</th>\
<td id="value-arc" class="popup-table-data"></td>\
</tr>\
<tr class="popup-table-row">\
<th class="popup-table-header">Current speed:</th>\
<td id="value-speed" class="popup-table-data"></td>\
</tr>\
</table>\
<button id="button-submit" type="button">Save Changes</button>\
</form>';
Use a stylesheet, keeps the template nice and clean:
.popup-table {
width: 100%;
}
.popup-table-row {
background-color: grey;
}
In the onEachFeature function, attach a click handler:
L.geoJson(collection, {
onEachFeature: function (feature, layer) {
layer.on('click', layerClickHandler);
}
});
And handle it:
function layerClickHandler (e) {
var marker = e.target,
properties = e.target.feature.properties;
// Check if a popup was previously set if so, unbind
if (marker.hasOwnProperty('_popup')) {
marker.unbindPopup();
}
// Create new popup from template and open it
marker.bindPopup(template);
marker.openPopup();
// Now that the popup is open and the template converted to HTML and
// attached to the DOM you can query for elements by their ID
L.DomUtil.get('value-arc').textContent = properties.arc;
L.DomUtil.get('value-speed').textContent = properties.speed;
var inputSpeed = L.DomUtil.get('input-speed');
inputSpeed.value = properties.speed;
L.DomEvent.addListener(inputSpeed, 'change', function (e) {
properties.speed = e.target.value;
});
var buttonSubmit = L.DomUtil.get('button-submit');
L.DomEvent.addListener(buttonSubmit, 'click', function (e) {
// Do fancy ajax stuff then close popup
marker.closePopup();
});
}
Example on Plunker: http://plnkr.co/edit/8qVoW5?p=preview
This is cleaner, faster, it doesn't bind popups to every marker. It's more readable, extendable and less error prone. I hope that help, good luck!

Related

Can't call jQuery function

I have a problem with my code.
I want to call a function but it's not working.
First, function show() displays button. This button has id='send' and it's inside the div with class='messagebox'. I want to call function on button click.
(I call function show in php script)
echo<<<ENDL
<div class="friendslistimgbox" onclick="show('$id','$login','$photo')">....</div>
ENDL;
$(.messagebox #send) or $(.messagebox > #send) are not working
$(document).ready(function(){
var conn = new WebSocket('ws://localhost:8080');
conn.onopen = function(e) {
console.log("Connection established!");
};
conn.onmessage = function(e) {
console.log(e.data);
var data = JSON.parse(e.data);
var row = data.from+": "+data.msg+"<br/>";
$("#chats").append(row);
};
$(".messagebox #send").click(function(){
var userId = $("#userId").val();
var msg = $("#msg").val();
var data = {
userId: userId,
msg: msg
};
conn.send(JSON.stringify(data));
})
})
function show(id,login,photo){
$('.messagebox').html("<input type='hidden' id='userId' value='"+login+"'><input type='text' id='msg' class='sendmessage'><button id='send' type='submit' class='button_sendmessage'><i class='icon-right-dir'></i></button>");
$('#message_to').html("<a href='"+login+"'><img src='../userphotos/"+photo+"'>"+login+"</a>");
$("#allmessagesbox").css("visibility","visible");
}
HTML /
<div class="allmessagesbox" id="allmessagesbox">
<div class="messages">
<div class="message_to" id="message_to"></div>
</div>
<div class="messagebox"></div>
</div>
<div id="chats"></div>
You'll need to use the .on() method to register events with DOM elements that are dynamic (ie like your button, which might exist in the future).
In the case of your code, you can use on() in the following way:
// Replace this line:
// $(".messagebox #send").click(function(){
// With this:
$("body").on("click", ".messagebox #send", function(){
var userId = $("#userId").val();
var msg = $("#msg").val();
var data = {
userId: userId,
msg: msg
};
conn.send(JSON.stringify(data));
})
This can basically be read and understood as:
// For any dynamic element in scope or child of the body
$("body")
// Register a click event with any element that matches the
// .messagebox #send selector either now, or in the future
.on("click", ".messagebox #send", function(){
...
}));
For more information on on(), see the jQuery documentation

Modifying URL with javascript

I have some simple code that allows you to enter Amazon isbns/asins and converts them to hyperlinks. These hyperlinks are Amazon.com searches for the said isbn/asin.
Example pic: http://imgur.com/a/rYgYt
Instead of the hyperlink being a search I would like the link to go directly to the products offer page.
The desired link would be as follows:
https://www.amazon.com/gp/offer-listing/ASIN/ref=dp_olp_used?ie=UTF8&condition=used
"ASIN" would be where the ASIN/ISBN would need to be populated to generate the link, for example:
Im asking if someone could help modify my existing code to create the change. My skills lack the ability to implement the change. The existing code is as follows:
<html>
<head>
</head>
<div><b>ISBN Hyperlinker</b></div> <textarea id=numbers placeholder="paste isbn numbers as csv here" style="width:100%" rows="8" >
</textarea> <div><b>Hyperlinked text:</b></div> <div id="output" style="white-space: pre"></div>
<input type="button" id="button" Value="Open All"/>
<script>
var input = document.getElementById('numbers');
var button = document.getElementById('button');
var output = document.getElementById('output')
var base =
'https://www.amazon.com/s/ref=nb_sb_noss?url=search-alias%3Daps&field-keywords='
var urls = []
//adding an event listener for change on the input box
input.addEventListener('input', handler, false);
button.addEventListener('click', openAllUrls, false);
//function that runs when the change event is emitted
function handler () {
var items = input.value.split(/\b((?:[a-z0-9A-Z]\s*?){10,13})\b/gm);
urls=[];
// Build DOM for output
var container = document.createElement('span');
items.map(function (item, index) {
if (index % 2) { // it is the part that matches the split regex:
var link = document.createElement('a');
link.textContent = item.trim();
link.setAttribute('target', '_blank');
link.setAttribute('href', base + item);
container.appendChild(link);
urls.push(base + item);//add the url to our array of urls for button click
} else { // it is the text next to the matches
container.appendChild(document.createTextNode(item))
}
});
// Replace output
output.innerHTML = '';
output.appendChild(container);
}
function openAllUrls(){
for(var i=0; i< urls.length; i++){//loop through urls and open in new windows
window.open(urls[i]);
}
}
handler(); // run on load
</script>
</html>
to modify output URL, replace
var base = ".....';
with
var basePrefix = 'https://www.amazon.com/gp/offer-listing/';
var baseSuffix = '/ref=dp_olp_used?ie=UTF8&condition=used';
and replace
base + item
with
basePrefix + item + baseSuffix

JS Created buttons are not defined when accessed later

I have a script that makes a button in a table every 5 seconds.
I originally had the button made with the onclick attribute which called a function in the script. This however, gave me an error saying that the function didn't exist, and as from what I've seen on here, it has been answered but I don't know how I'd fix it in my situation. I switched it so that Javascript handles for the button click. I added attributes to the button tag to grab when the btnTeamListAction function is called. The console prints the following,
control.js:86 Uncaught TypeError: Cannot set property 'onclick' of null
at window.onload (control.js:86)
JS Snippets:
#button click handler
btnTeamListAction.onclick = function(){
var id = this.getAttribute("data-team-id");
var isRedo = this.getAttribute("data-is-redo");
teamListSelect(id,isRedo);
}
#the function that creates the buttons
function appendTeamTable(id,name,finished){
var finished_txt;
var action_content;
if(finished == 1){
finished_txt = "Yes";
action_content = '<button id="teams-list-action" data-team-id="'+id+'" data-is-redo="1">Retime</button>';
}
else {
finished_txt = "No";
action_content = '<button id="teams-list-action" data-team-id="'+id+'" data-is-redo="0">Time</button>';
}
var tr = document.createElement('tr');
tr.innerHTML ='<td>'+ id +'</td><td>'+ name +'</td><td>'+ finished_txt +'</td><td>'+ action_content +'</td>'
teamTable.appendChild(tr);
var btnTeamListAction = document.getElementById("teams-list-action");
btnTeamListAction.onclick = function(){
console.log("ActionClicked");
var id = this.getAttribute("data-team-id");
var isRedo = this.getAttribute("data-is-redo");
teamListSelect(id,isRedo);
}
}
I've tried browsing this form for this error and have found many related questions but not for this particular case with the button being created by JS itself.
Please ask if you need the full script or HTML, Thanks!
function appendTeamTable(id,name,finished){
var finished_txt;
var action_content= document.createElement("a");
var btn = document.createElement("button");
btn.setAttribute("id","teams-list-action");
btn.setAttribute("data-team-id",id);
if(finished == 1){
finished_txt = "Yes";
var t = document.createTextNode("Retime");
btn.setAttribute("data-is-redo","1");
}
else {
finished_txt = "No";
var t = document.createTextNode("Time");
btn.setAttribute("data-is-redo","0");
}
btn.appendChild(t);
btn.addEventListener("click",function(){
var id = this.getAttribute("data-team-id");
var isRedo = this.getAttribute("data-is-redo");
teamListSelect(id,isRedo);
});
action_content.appendChild(btn);
var tr = document.createElement('tr');
var td = document.createElement('td');
td.appendChild(action_content);
tr.innerHTML ='<td>'+ id +'</td><td>'+ name +'</td><td>'+ finished_txt +'</td>'
tr.appendChild(td);
teamTable.appendChild(tr);}
I looked at the post here and took the idea from the second answer and put a event handler on the table itself instead of the buttons individually. It's works like a charm now. Thanks all three of you for attempting to look through my seriously messed up code! :)

i want to use addEvent instead of onkeyup in html

<td valign="top"><center>
<textarea id="ta_in" rows="7" cols="42" onkeyup="get_ml()"></textarea><br>
<textarea id="ta_out" rows=7" cols="42"></textarea></center>
</td>
//javascript file.
function get_ml()
{
en = "|" + document.getElementById("ta_in").value;
ml = "";
n = 0;
.....
.....
.....
document.getElementById("ta_out").value = ml;
}
//i need to use addEvent instead of onkeyup
For modern browser compatibility, you would use addEventListener like this:
document.getElementById("ta_in").addEventListener("keyup", function(e) {
var en = "|" + document.getElementById("ta_in").value;
var ml = "";
var n = 0;
.....
.....
.....
document.getElementById("ta_out").value = ml;
});
Working demo: http://jsfiddle.net/jfriend00/6QMFV/
You would just run this code after your page has been loaded, by either placing the code at the end of your page (just before </body>) or by putting it in a function that you call from just before </body> or by calling this code for an event handler that listens for an event that tells you the page is loaded.

How to delete a created element in JavaScript?

Hello I have a piece of code that allows me to add an author.
I have a problem, I can't seem to delete the created node in my table
This is the worst frustration in my life. I could not seem to delete it.
I also have notice that every time I inspected the element I could not see the
new created element from the source. But when I view it on firebug I can actually see it there.
Adding an input element and appending it on the table works fine for me.
I am just very new to JavaScript and to this web thingy and deleting a CREATED ELEMENT via .createElement is where I am stuck at.
here is my code
<script>
var ctr = 1;
function showTextBox()
{
// is the table row I wanted to add the element before
var target = document.getElementById('bef');
var tblr = document.createElement('tr');
var tbld1 = document.createElement('td');
var tbld2 = document.createElement('td');
var tblin = document.createElement('input');
tblin.name = 'Author' + ctr;
tblin.id = 'Author' + ctr;
tblin.placeholder = 'add another author';
tbld1.appendChild( document.createTextNode('Author' + ctr ) );
tbld2.appendChild( tblin );
tblr.appendChild( tbld1 );
tblr.appendChild( tbld2 );
target.parentNode.insertBefore( tblr , target );
ctr++;
}
function hideTextBox()
{
var name = 'Author'+ctr;
var pTarget = document.getElementById('tbhold');
var cTarget = document.getElementById( name );
alert( cTarget ); // this one return null? Why? I have created id="Author1"
// viewing this code on source make the created elem to not appear
}
</script>
Am I doing something wrong? I really need help. This is for my project at school.
Is there any way I could delete it. I created that node and I want it to be deleted when I click something.
Also I prefer to stay with JS not with JQuery or other JStuff and I am disregarding compatibility for now because this is just a sample in my dummy form. I will deal on that later.
EDIT
In case you need the actual form here it is
<form enctype="multipart/form-data" action="process/" method="POST" />
<h3>Book Upload</h3>
<table border="2" id='tbhold'>
<tr>
<td>Title</td>
<td><input type="text" id="book_title" name="book_title" /></td>
</tr>
<tr>
<td>Author</td>
<td><input type="text" id="book_author" name="book_author" /></td>
</tr>
<tr id="bef">
<td colspan="2">
add author
remove
</td>
</tr>
</table>
</form>
Thank you very much!
Try this function:
function removeElements(elements){
for(var i = 0; i < elements.length; i++){
elements[i].parentNode.removeChild(elements[i]);
}
}
Then you can do this:
removeElements(document.querySelectorAll('#tbhold tr'));
function hideTextBox(){
var name = "Author" + (ctr - 1);
var pTarget = document.getElementById('tbhold');
var cTarget = document.getElementById(name);
var tr = cTarget.parentNode.parentNode;
tr.parentNode.removeChild(tr);
ctr = ctr - 1;
}
Here is a demo
every time I inspected the element I could not see the new created element from the source. But when I view it on firebug I can actually see it there.
If you change the DOM, you of course do not change the HTML source markup. Only the DOM inspector will show you the changes.
var name = 'Author'+ctr;
var cTarget = document.getElementById( name );
alert( cTarget ); // this one return null? Why? I have created id="Author1"
Yes, you created it using your showTextBox function. But that did also increment the ctr to 2, so that you now are looking for Author2 which obviously does not exist. So put a ctr--; before it and it should work.

Categories

Resources