I have a table being loaded from a JSON array, but my click event solution does not seem to work. As the loop is cycled through, I add a click event to each listener to each of the new added divs.
document.getElementById(i.toString()).addEventListener("click", function(event)
{
console.log(event);
});
The issue is only the last element responds to the clicks.
My code is available on pastebin
This is happening because of the way you are currently trying to add new elements to your html.
Replace this (what you are currently doing):
nw.innerHTML = nw.innerHTML + "<div class='" + nodeType + "' id='" + i + "'><div class='nodeName'>" + json[i][0] + "</div></div>";
With this:
var div = document.createElement("div");
div.setAttribute("class", nodeType);
div.setAttribute("id", i.toString());
div.innerHTML = '<div class="nodeName">' + json[i][0] + '</div>';
nw.appendChild(div);
Here's a fiddle that shows a simpler version of this working.
In my opinion,
nw.innerHTML = nw.innerHTML + "<div class='" + nodeType + "' id='" + i + "'><div class='nodeName'>" + json[i][0] + "</div></div>";
this code override previous nw's elements and their event listeners too.
Therefore, instead of using innerHTML, try to use document.createElement("div") and append it to nw using appendChild(). It works in my test.
Related
I have a snippet of my jQuery code;
$('#elements').on('click', '.items', function () {
var content, id, tag;
tag = this.tagName;
id = $('#' + this.id);
content = id.html();
switch (tag.substr(0, 1)) {
case "P":
id.html("<textarea id='" + this.id + "In' class='" + tag + "In' type='text'>" + content + "</textarea>");
break;
case "H":
id.html("<input id='" + this.id + "In' class='" + tag + "In' value='" + content + "' >");
break;
}
});
The purpose of this is when I click on a paragraph tag, it will add a text area inside of the paragraph tag (with the content inside it ready for editing). When I click a heading tag, it will create an 'input' tag with the content inside it for editing.
Unfortunately, when i click twice on the paragraph, it adds a text area with the content inside it as it should but on the second click it adds another text area inside of that, now the 'content' of the textarea is: <textarea id="2In" class="PIn" type="text">Paragraph one. and with every click it adds: <textarea id="2In" class="PIn" type="text">
I understand this is happening as it should given the code but I want to stop the click event on that specific ID (this.id) but keep the click event active on the other elements with the class '.items'.
**Additionally: **
I'm sure this is bad practice to approach this by creating the editiable tags inside of the old ones so if anyone has a better approach be sure to let me know.
Many thanks,
Mike
I'd probably solve it by adding a :not(.clicked) to the selector, and adding that class when you add the input. E.g.:
$('#elements').on('click', '.items:not(.clicked)', function () {
$(this).addClass("clicked");
// ...your current handling...
});
But you could solve it by checking for the existence of the field, provided the input or textarea you're adding is the only one the paragraph will have:
$('#elements').on('click', '.items', function () {
if (!$(this).find("input, textarea")[0]) {
// ...your current handling...
}
});
Or actually jQuery extends CSS to provide :has and to allow :not to have more complex contents, so in theory this would work:
$('#elements').on('click', '.items:not(:has(input)):not(:has(textarea))', function () {
// ...your current handling...
});
...but that selector is getting a bit unwieldy...
What about using .one?
By using one, the click event can only be triggered once. Here's an example.
$('#elements > *').one('click', function () {
var content, id, tag;
tag = this.tagName;
id = $('#' + this.id);
content = id.html();
switch (tag.substr(0, 1)) {
case "P":
id.html("<textarea id='" + this.id + "In' class='" + tag + "In' type='text'>" + content + "</textarea>");
break;
case "H":
id.html("<input id='" + this.id + "In' class='" + tag + "In' value='" + content + "' >");
break;
}
});
But it seems you are trying to do something like allowing a user to edit text and saving the new input. I'd advise using a combination of contenteditable and localStorage.
I have this script:
function downloadIt() {
var dataUri = "data:application/csv;charset=utf-8,Col1%2CCol2%2CCol3%0AVal1%2CVal2%2CVal3%0AVal11%2CVal22%2CVal33%0AVal111%2CVal222%2CVal333"
var filename = "somedata.csv"
$("<a download='" + filename + "' href='" + dataUri + "'></a>")[0].click();
}
It works on Chrome but doesn't work on Firefox, without any error on the console. What is the cause and how to fix this?
Appending the element on the body solves the problem, just replace line 3 on the question above into this:
// store the element to a variable
var x = $("<a download='" + filename + "' href='" + dataUri + "'></a>");
// append to body
x.appendTo('body');
// click it (download)
x[0].click();
// remove from body
x.remove();
It seems that firefox won't execute the click event when the element not attached to the body
I got a little problem in my code, I try to launch a function in the content of a InfoWindow in javascript, and, I don't know why, I got difficulties to do that. I've looked at a lot of topics about it on stackoverflow and elsewhere, applied exactly what I've seen on these topics but...
Note: this is a part of my entire code, this is why "infobulle" doesn't seem to be declared.
In the same way, "this.jsonActivity" and "mapView" are correctly initialized before this part of code.
Here, "newActivity" in parameter is a Marker from the google maps API, and what I'm trying to do is to display an InfoWindow next to the current marker when we click on it. Everything's ok, the entire text is correctly displayed in the InfoWindow but the problem is that I can't call the "alertMessage()" method when I click on the button, nothing happens... and I really don't know why !!
Well, here's my code, thank you for your help :)
google.maps.event.addListener(newActivity, "click", function() {
if(infobulle)
infobulle.close();
var contenu = '<strong>' + this.jsonActivity.title + '</strong><br/>' +
this.jsonActivity.description + '<br/>' +
'<h3>Routing:</h3>' +
'<button onclick="alertMessage()">Click me</button>';
infobulle = new google.maps.InfoWindow({
content: contenu,
maxWidth: 120
});
infobulle.open(mapView, this);
function alertMessage() {
alert("alertMessage");
}
});
EDIT:
this is perfect, it's working now!
I've tried all of your solutions and only one is working for me, the one that declares the function as global, thanks to Dr.Molle!
Now I put what I've tried for the two other solutions:
google.maps.event.addListener(newActivity, "click", function() {
if(infobulle)
infobulle.close();
var contenu = '<strong>' + this.jsonActivity.title + '</strong><br/>' +
this.jsonActivity.description + '<br/>' +
'<h3>Routing:</h3>' +
'<button id="myAlert">Click me</button>';
infobulle = new google.maps.InfoWindow({
content: contenu,
maxWidth: 120
});
infobulle.open(mapView, this);
document.getElementById("myAlert").addEventListener(function() {
alert("something");
});
});
For the solution suggested by Jared Smith. It's like before, everything is correctly displayed except for the button when I click on it, nothing happens.
And for the solution suggested by Alexander:
google.maps.event.addListener(newActivity, "click", function() {
if(infobulle)
infobulle.close();
var contenu = '<strong>' + this.jsonActivity.title + '</strong><br/>' +
this.jsonActivity.description + '<br/>' +
'<h3>Routing:</h3>' +
'<button onclick="(function() {
alert(\"something\");
})();">Click me</button>';
infobulle = new google.maps.InfoWindow({
content: contenu,
maxWidth: 120
});
infobulle.open(mapView, this);
});
and this time, even the elements where I'm supposed to click the button don't appear...
Well for these two solutions, maybe I don't have used them correctly... so if you find something to say, please go ahead :)
EDIT(2):
Okay now I've got an other question: if I want to put a variable as parameter of the function, how am I supposed to do this? Just typing the name of the variable as parameter does not working.
I've tried:
var contenu = '<strong>' + this.jsonActivity.title + '</strong><br/>' +
this.jsonActivity.description + '<br/>' +
'<h3>Routing:</h3>' +
'<button onclick="alertMessage(\'something\')">Click me</button>';
window.alertMessage = function(thing) {
alert(thing);
};
which is working because I put directly the string as parameters.
But if I declare:
var text = "something";
var contenu = '<strong>' + this.jsonActivity.title + '</strong><br/>' +
this.jsonActivity.description + '<br/>' +
'<h3>Routing:</h3>' +
'<button onclick="alertMessage(text)">Click me</button>';
window.alertMessage = function(thing) {
alert(thing);
};
It's not working anymore, do you know how to fix this?
make the function global accessible(currently it isn't):
window.alertMessage=function() {
alert("alertMessage");
}
Instead of
"<button onclick='blah'>"
You need
"<button id='myAlertButton'>"
Then in your eventListener callback after the infoWindow is added to the DOM
document.getElementById('myAlertButton').addEventListener(function(){
alert('Whatever');
});
The InfoWindow accepts an HTMLElement node as its content option. So you can build your HTML via JS and add the event JS-land, e.g.:
// Create Nodes
const ul = document.createElement('ul');
const setOrigin = document.createElement('li');
// Set hierarchy
ul.appendChild(setOrigin);
setOrigin.appendChild(document.createTextNode('Set Origin'));
// Add event listener
setOrigin.addEventListener('click', () => console.log('Set origin and so on…'));
// Set root node as content
const contextMenu = new google.maps.InfoWindow({
content: ul,
});
The aim is to append a line of text into the element below.
anchorElement = "<a id='anchor" + countWide + "' class=\"boxOPT oneplustwo\" alt=\'"+ image_website +"' style=\"cursor:pointer;width:"+ itemWidth + "px"+";height:"+anchorHeight+";position:absolute;left:"+ locationLeft + "px"+";top:0.3%;\" ><p class=\"popupDynamic\"> " + popupImageTitles[i] + "</p>";
this code is contained within a loop so each time a new anchor is created and given an incremented ID (countwide) for for example 'anchor1' 'anchor2'
What I need is to be able to append this variable below as part of the p element inside this anchor
image_price
I have tried this with no progress.
$("#anchor1").append(image_price);
obviously we need the id in the line above to increment in line with the loop.
Thanks.
Try:
$("#anchor" + countWide + " .popupDynamic").append(image_price);
Explanation:
I have just updated the selector so that it would pick up the child of the #anchor + countWide(this means anchor plus the dynamic ID) with the class of .popupDynamic and append the price to it.
You can use the countWide variable in your selector, this way :
$("#anchor"+countWide+" .popupDynamic").append(image_price);
I have a JavaScript function:
function addTool(id, text, tool, pic) {
var container = getById('infobox');
var origimg = getById('tempimg').src;
container.innerHTML += "<div id='" + id + "' class='toolText'>" + text + "<br><img class='toolImg' src='img/tools/" + tool + "'></div>";
getById(id).setAttribute('onMouseOver', "mOver('"+ id +"', '" + pic + "');");
getById(id).setAttribute('onMouseOut', "mOut('"+ id +"', '" + origimg + "');");
getById(id).setAttribute('href', 'javascript:mClick(id);');
}
Which generates several divs, using this code:
addTool("1p", "Bar", "tool1.jpg", 'img/p&g-part-2_skiss1-2.jpg');
addTool("2p", "Tube", "tool1.jpg", 'img/p&g-part-2_skiss1-2.jpg');
addTool("3p", "Rotating", "tool1.jpg", 'img/p&g-part-2_skiss1-2.jpg');
The mouse events work fine in all major browsers except IE. It seems that all divs except the last will have the mouse event in lowercase which will have the mouse event exactly as written, with upper case letters.
All mouse events will fire except for the last div, even if I write onmouseover instead of say ONmouseOVER, which works fine on all except the last.
Do not use setAttribute to add events. Use attachEventListener/addEvent
The problem you have is adding the elements to the div. You are basically wiping it away each time when you are adding the new elements. That is bad. You should be using appendChild to add new content to the div.
Basic idea:
function attachEvent(elem, eventName, fn) {
if ( elem.attachEvent ) {
elem.attachEvent( 'on' + eventName, fn);
} else {
elem.addEventListener( eventName, fn, false );
}
}
function addTool(text, message) {
var container = document.getElementById('infobox');
var newTool = document.createElement("a");
newTool.innerHTML = text;
newTool.href="#";
var myClickFnc = function(e) {
alert(message);
return false;
}
attachEvent(newTool, "click", myClickFnc);
container.appendChild(newTool);
}
addTool("cat","meow");
addTool("dog","bark");
addTool("pig","oink");
running example
Just as #epascarello pointed out, it seems that the setAttribute was the culprit, so I resolved it by setting the events in inline, such as this:
function addTool(id, text, tool, pic) {
var container = getById('infobox');
var origimg = getById('tempimg').src;
container.innerHTML += "<div id='" + id + "' class='toolText'" +
"onmouseover=\"mOver('"+ id +"', '" + pic + "');\" " +
"onmouseout=\"mOut('"+ id +"', '" + origimg + "');\" " +
"onclick=\"mClick(id);\"" +
">" + text + "<br><img class='toolImg' src='img/tools/" + tool + "'></div>";
}
Which worked just fine in all browsers, including IE.
You could do this part with JQuery:
$("#"+ id).mouseover(function() {
mOver('"+ id +"', '" + pic + "');
});
You can even take this a lot further:
https://stackoverflow.com/a/4158203/190596