"click" for a dynamically created link isn't getting triggered - javascript

I want to add a link dynamically and attach "onclick" event on it. Here's a simplified version of what I have:
for (var i = 0; ....) {
var a1 = document.createElement("a");
a1.innerHTML = "My link123";
a1.addEventListener("click", function(event) {
myFunc(someArray[i].property1, event);
// alert("test123");
});
var p1 = document.createElement("p");
var sp1 = document.createElement("span");
//..........
divContainer.innerHTML += a1.outerHTML + p1.outerHTML + sp1.outerHTML;
}
But it doesn't trigger the "click" event when I click on it.
update:
after it's created and I click on it, I get:
myFunc(someArray[i].property1, event); -- Cannot read property 'property1' of undefined
I guess it's something related to how clojures are evaluated.
update2
I've tried this:
a1.addEventListener("click", function(event) {
(function(i2){
myFunc(i2, event);
})(myArray[i].property1);
});
But it said at runtime when I clicked on it "property1 isn't defined"; How can I fix that?

divContainer.innerHTML += a1.outerHTML + p1.outerHTML + sp1.outerHTML;
You are serialising the DOM nodes (both the new ones and the ones already in divContainer) to HTML, which doesn't include the event listeners, and then creating new DOM nodes from the HTML.
Use appendChild and friends instead.
divContainer.appendChild(a1);
divContainer.appendChild(p1);
divContainer.appendChild(sp1);

Related

Why does my button click listener not work in chrome extension?

I'm trying to create a chrome extension, my problem is that when I try to place an event listener to each button in a class, only the first button has one, and the rest don't have an event listener.
function copyButtonInitialise(){
var copyButtons = document.getElementsByClassName("copyPassword");
console.log("length = ", copyButtons.length);
for (var i = 0; i < copyButtons.length; i++){
console.log(copyButtons[i] + " element number " + i + "= button");
copyButtons[i].addEventListener("click", copyButtonClick);
}
}
This function is what should be called if any button with the class "copyPasword" is clicked.(just want to make sure it gets clicked, but it doesn't)
function copyButtonClick(){
console.log("Hello There");
}
This is the function that loads passwords, it's called before adding event listeners to buttons.
async function loadPasswords(){
document.getElementById("passwordTable").innerHTML = "";
console.log("This is the loadpasswords function");
chrome.storage.sync.get(null, function(items) {
var allKeys = Object.keys(items);
var passwordTable = document.getElementById("passwordTable");
var header = passwordTable.createTHead();
var passwordRow = header.insertRow(0);
for(var i = 0; i < allKeys.length; i++){
let passwordKey = allKeys[i];
chrome.storage.sync.get([allKeys[i]], function(value){
var passwordName = Object.keys(value);
passwordName = passwordName[0];
var table = document.getElementById("passwordTable");
var header = table.createTHead();
var passwordRow = header.insertRow(0);
var cellTwo = passwordRow.insertCell(0);
var cell = passwordRow.insertCell(1);
cellTwo.innerHTML = "<p1 id=passwordNameCol>" + passwordName + "</p1>";
cell.innerHTML = "<button class=copyPassword> Copy " + '"'+ passwordName + '"'+ "</button>";
});
}
});
}
The passwords clearly load in.
When I click the buttons, nothing gets sent to the console, expecting a "hello there" (as shown above)
Try these things:
the outer chrome.storage.sync.get(null returns all stored couples key+value.
Why you use chrome.storage.sync.get a second time inside the "for" statement? It is not necessary.
Don't use insert methods of table but try with createElement and appendChild.
Create first an THEAD (or TBODY) element and then put every rows on it.
When you'll finish you'll have to append only that THEAD\TBODY as child of your table.
Try to create the button with createElement (as i suggest for any other table elements) and after its creation put the event listener on it (inside the "for").
if you think to reuse the same table for other differente rows remenber to destroy the THEAD first otherwise the just created events listeners will remain orphans.
Destroy the THEAD with something like element.remove() and not with innerHTML = "".

Adding events and functions on elements generated with createElement()

I created different elements-paragraphs with createElement()/createTextNode() and added them to the body.
My problem is that i want to make those divs links or be able to add events such as onclick and obviously there is no HTML code to do that..just javascript generated objects.
my code atm:
for (i=0; i<10; i++){
var newDiv = document.createElement("div");
newDiv.className = "block";
var heading = document.createElement("h2");
var newContent = document.createTextNode(data[1][i]);
heading.className="title";
heading.appendChild(newContent);
newDiv.appendChild(heading);
var paragraph = document.createElement("p");
var newContent2 = document.createTextNode(data[2][i]);
paragraph.className="light";
paragraph.appendChild(newContent2);
newDiv.appendChild(paragraph);
var currentDiv = document.getElementById("div1");
document.body.insertBefore(newDiv, currentDiv);
}
You can add the event listener to the object you just created. The object does not have to be HTML. Read more about adding event listeners and see simple example:
var someDiv = document.createElement('div');
var txt = document.createTextNode('click me');
someDiv.append(txt);
document.body.append(someDiv);
var myFancyFunction = function() {
alert('you clicked me');
};
someDiv.addEventListener('click', myFancyFunction);
Update after your code you can add an event listener to those objects you create on the fly. You can also add different functions on the same event. In this case it's the same function for both elements/objects .. play with this: (I changed the data to "dummy data" as there was no data)
var myClick = function(event) {
alert(event.target.innerHTML);
};
for (i=0; i<10; i++){
var newDiv = document.createElement("div");
newDiv.className = "block";
var heading = document.createElement("h2");
var newContent = document.createTextNode('dummy data1 index: ' + i);
heading.className="title";
heading.appendChild(newContent);
newDiv.appendChild(heading);
var paragraph = document.createElement("p");
var newContent2 = document.createTextNode('dummy data2 index: ' + i);
paragraph.className="light";
paragraph.appendChild(newContent2);
newDiv.appendChild(paragraph);
var currentDiv = document.getElementById("div1");
document.body.insertBefore(newDiv, currentDiv);
heading.addEventListener('click', myClick);
paragraph.addEventListener('click', myClick);
}
You can simply call addEventListener on the JS-generated objects, even before they are inserted into the DOM, or are never inserted at all:
let div = document.createElement('div');
div.addEventListener('click', function(event) {
// do something
});
// This will trigger a call of the registered click callback,
// regardless of whether the div is in the DOM:
div.dispatchEvent(new Event('click', {
"bubbles": true,
"cancelable": false,
}));
// To add it to the DOM, simply add it the way you wish:
document.body.appendChild(div);
EventTarget.dispatchEvent allows you to trigger an event in a computational way (has equivalent effect to actually clicking the div)
Do take note of the browser compatibility of the event constructor in the example above.
Once an element is added to the dom, you can select it just like any other element.
// Create the element
var paragraph = document.createElement('p');
// Give it an `id`
paragraph.id = 'foo';
// Add the element to the `dom`
document.body.appendChild(paragraph);
// Add the listener
paragraph.addEventListener('click', function() {
this.innerHTML = 'It was clicked';
});
p {
height:20px;
padding:10px;
outline:1px solid #bada55;
}
In the example above, I added an id. If for some reason you need to re-select the element it may make it easier.

Change InnerHTML based on anchor click

I'm a little new to Web Development so I was hoping someone could answer this for me.
I'm building a prototype for a "Web Messenger" similar to Facebook messenger. I have a sidebar that I populate with a UL of anchor tags when the window loads and it looks like this. Here is the code for it
var toAdd = document.createDocumentFragment();
var newUL = document.createElement('ul');
newUL.id = 'menu-content';
newUL.className = 'menu-content collapse out';
for(var i = 0; i < 5; i++){
var newLI = document.createElement('li');
var newA = document.createElement('a');
newA.id = 'chat' + i;
newA.setAttribute('href', "#");
newA.innerHTML = "Chat" + (i + 1);
newLI.appendChild(newA);
newUL.appendChild(newLI);
}
toAdd.appendChild(newUL)
document.getElementById("menu-list").appendChild(toAdd);
I also have a Div at the top of the page which will display some details about the current chat, but for the time being will simply display the name of the chat, same as on the anchor tags.
Now based on another StackOverflow post the correct way to call a JS function from an anchor tag is
var c0 = document.getElementById("chat0");
//Set code to run when the link is clicked
// by assigning a function to "onclick"
c0.onclick = function(id) {
//Change Title Name here
//Do other stuff in the future
return false;
}
However I could have 20+ chats on the sidebar at any one time, so this seems like a lot of repetitive code to write.
Is there a better way to do this?
Give your chats a general class instead example chat then attach the click event to all the chat's in the same time using .getElementsByClassName().
So you could add className just after newA.id :
newA.id = 'chat' + i;
newA.className = 'chat';
Then attach the click event :
var chats = document.getElementsByClassName('chat');
for (var i=0; i < chats.length; i++) {
chats[i].addEventListener('click', chatClick, false);
}
function chatClick(){
//chat is clicked
//The 'this' object here refer to clicked element
}
You could use .addEventListener() instead of onclick.
NOTE : You can attach the click event directly after node creation :
for(var i = 0; i < 5; i++){
var newLI = document.createElement('li');
var newA = document.createElement('a');
newA.id = 'chat' + i;
newA.setAttribute('href', "#");
newA.innerHTML = "Chat" + (i + 1);
newA.addEventListener('click', chatClick, false); //Attach click event HERE
newLI.appendChild(newA);
newUL.appendChild(newLI);
}
Hope this help.
Yap sure. You can give them all a class and after load just use a simple jQuery code to bind onclick for all of them:
$('a.className').click(function() {
// Your code here
});
Now if the a tags are added after execution of the code you just simply need to call this again or bind to those elements manually.

DOM: Delete newly created 'article' element with newly created delete button within onclick event?

I have one section element that contains one article element. Also, I have one input button with 'onclick' event. Whenever this event fired, a new article element appended to the section element with unique id.
The newArticle element contains a label, text box and a delete button. All these three elements get created within the on-click event.
document.getElementById("addRow").onclick = function () {
var newCustomerlbl = document.createElement("label");
newCustomerlbl.innerHTML = "Cutomer Name: ";
var newCustomertxt = document.createElement("input");
newCustomertxt.setAttribute("type", "text");
var delBtn = document.createElement("input");
delBtn.setAttribute("type", "button");
delBtn.setAttribute("value", "Delete");
delBtn.setAttribute("id", "btnDelete");
var newArticle = document.createElement("article");
newArticle.appendChild(newCustomerlbl);
newArticle.appendChild(newCustomertxt);
newArticle.appendChild(delBtn);
var customerSection = document.getElementById("customerRecords");
var customerArticles = customerSection.getElementsByTagName("article");
for (var i = 0; i < customerArticles.length; i++) {
var lastDigit = i + 1;
var newArticleValue = "article" + lastDigit;
newArticle.setAttribute("id", newArticleValue);
}
customerSection.appendChild(newArticle);
}
Now what I want is whenever user click upon the newly created appended delete button, only that particular article get deleted without effecting the rest of articles.
Here is the my jsFiddle code.
If you don't want to use jQuery you can add event listeners to your buttons:
delBtn.addEventListener('click', function () {
this.parentElement.remove();
}, false);
https://jsfiddle.net/3nq1v5e1/
You need to bind an event listener on the newly created delete button. Your example code about using $(this) suggest that you are using JQuery, but then again in the rest of the code you are not using any JQuery?
If you are using JQuery, things get real simple, just add something like
$(document).on('click','.btnDelete', function(){
$(this).closest('article').remove();
});
(and remember to give the deletebutton a CLASS rather than ID, as there will be multiple delete buttons).
If you are NOT using JQuery, you need to add the event listener EVERY TIME a new delete button is created
newArticle.appendChild(delBtn);
delBtn.onclick = function(.....
etc.

Attaching Click Event to DIV Using jQuery Library

I am aware I can use the click function to attach an event to the DIV element but for some reason it is not working for me. Here is how I am creating the DIV element.
function createColorSwatchDiv(color) {
var colorSwatchDiv = $("<div>");
var image = $("<img>");
image.attr("src",color.imageURL);
var label = $("<label>");
label.text(color.title);
colorSwatchDiv.append(image);
return colorSwatchDiv;
}
Then I try to attach the click event like the following:
// run a loop and build the grid layout
for(index = 0; index < colors.length; index++) {
var colorSwatchDiv = createColorSwatchDiv(colors[index]);
// attach the event
colorSwatchDiv.click(function(){
alert('hello world');
});
colorsSection.append(colorSwatchDiv);
}
// add to the dom
$("#color .imageChartOption").after(colorsSection);
But it does not work and no click event is been attached.
following is the code
var $newdiv1 = $("<div id='object1' onClick=Test()>Hello</div>");
$("body").append($newdiv1);
function Test()
{
alert("Clicked");
}
OR
$newdiv1.on('click',function(){alert("hello");});
since you have created the div in a jQuery wrapper you don't need to wrap it again here $(colorSwatchDiv).click(.... Also, are you sure that the colorSwatchDiv variable is referencing the dom element and not the in memory element? Can you apply a class or anything to the elm in the dom?

Categories

Resources