'onclick' event handler created in javascript is not working - javascript

The 'click' event listener is not being added to the button.
The buttons do appear correctly with the other attributes. I have searched for a while and haven't been able to find a solution.
const connectedFriendsList = document.querySelector('#connected-friends-list');
function openMessengerWith(){
var friend_id = this.value;
console.log('Opening messenger with : ', friend_id);
}
// =======================================================
// Create elements and render friends list
//
var but;
function renderFriendsList(doc){
console.log('Rendering friend...');
but = document.createElement("input");
but.setAttribute("value", doc.id);
but.setAttribute("type", 'button');
but.id = doc.id;
but.addEventListener('click', function(){
openMessengerWith();
}, false);
console.log(but);
connectedFriendsList.appendChild(but);
console.log('Friend listed.');
}
The renderFriendsList function is being called down at the bottom.
firestore.collection('Users').doc(uid).collection('Friends').get().then((snapshot) => {
snapshot.docs.forEach(doc => {
renderFriendsList(doc);
})
});
EDITED:
function openMessengerWith(value){
var friend_id = value;
console.log('Opening messenger with : ', friend_id);
}
function renderFriendsList(doc){
console.log('Rendering friend...');
var but = document.createElement("button");
but.setAttribute("value", doc.id);
but.setAttribute("type", 'button');
but.id = doc.id;
but.innerHTML = doc.id;
connectedFriendsList.appendChild(but);
attachClickEvent(doc.id);
console.log('Friend listed.');
}
function attachClickEvent(value){
var test1 = document.getElementById(value);
console.log('current obj',test1);
document.getElementById(value).addEventListener("click",
function(){
openMessengerWith(value);
});
console.log('click events attached');
}
LOG:
Here is the updated log. As you can see the buttons are created. However, the event listeners are not being attached.
Rendering friend... messagesmain.js:71
current obj <button value=​"6r7CllAhMhPgmrhhjx1aneBCBbc2" type=​"button" id=​"6r7CllAhMhPgmrhhjx1aneBCBbc2">​6r7CllAhMhPgmrhhjx1aneBCBbc2​</button>​
messagesmain.js:76
click events attached messagesmain.js:56
Friend listed. messagesmain.js:48
Rendering friend... messagesmain.js:71
current obj <button value=​"J1EbJJ9iZKTspqiSKawZN7i5pPh2" type=​"button" id=​"J1EbJJ9iZKTspqiSKawZN7i5pPh2">​J1EbJJ9iZKTspqiSKawZN7i5pPh2​</button>​
messagesmain.js:76
click events attached messagesmain.js:56
Friend listed. messagesmain.js:48
Rendering friend... messagesmain.js:71
current obj
<button value=​"xSLBN2BqVocemn0OWOKh2UGY8Pt1" type=​"button" id=​"xSLBN2BqVocemn0OWOKh2UGY8Pt1">​xSLBN2BqVocemn0OWOKh2UGY8Pt1​</button>​
messagesmain.js:76
click events attached messagesmain.js:56
Friend listed.

If you want to get the value of input, use this is a good idea. But you need to know the reference of this.
In your code, the reference of this is window, not <input> tag.
That's why you can't get the value.
So you need to pass this.value into function openMessengerWith
but = document.createElement("input");
but.addEventListener('click', function() {
let value = this.value;
openMessengerWith(value);
}, false);
function openMessengerWith(value){
var friend_id = value;
console.log('Opening messenger with : ', friend_id);
}
connectedFriendsList.appendChild(but);

Related

How to get value of button with JS

How can I get the value of a button when there are many multiple buttons created? Currently on my Javascript file I have it so my search history makes a button in a list with a "value" of the city that is labeled.
When I click on the button that was made I get undefined.
function recentSearch(city) {
var addCity = document.createElement("button");
addCity.setAttribute("value", city);
addCity.textContent = city;
document.getElementById("searchHistory").append(addCity);
cities.push(city);
localStorage.setItem("searches",JSON.stringify(cities));
}
If you're adding so many buttons use event delegation. Add one listener to the parent container, add your buttons, and then, in the listener function, check to see if the clicked element is a button, and log its value.
const searchHistory = document.querySelector('#searchHistory');
// Add one listener to the container that calls `handleClick`
searchHistory.addEventListener('click', handleClick, false);
function handleClick(e) {
// Destructure the nodeName and value from
// the clicked element, and log the value if the
// element is a button
const { nodeName, value } = e.target;
if (nodeName === 'BUTTON') {
console.log(value);
}
}
function recentSearch(city) {
var addCity = document.createElement('button');
addCity.value = city;
addCity.textContent = city;
searchHistory.append(addCity);
}
const cities = ['London', 'Rome', 'New York', 'Seoul', 'Kingston'];
for (const city of cities) {
recentSearch(city);
}
<div id="searchHistory"></div>
The following code will log the value of the button to the console when it is clicked.
function recentSearch(city) {
var addCity = document.createElement("button");
addCity.setAttribute("value", city);
addCity.textContent = city;
addCity.onclick = (e)=>{
console.log(e.target.getAttribute('value'));
//or whatever other code you want to do onclick
}
document.getElementById("searchHistory").append(addCity);
cities.push(city);
localStorage.setItem("searches",JSON.stringify(cities));
}
Try using data-attributes. They make your code easier to read and provide a great way to pass along data inside of elements - and you can access their data using element.dataset.<attribute_name> - in this case e.target.dataset.value (from within the buttons click listener).
cities = []
function recentSearch(city) {
// FOR DEMO ONLY::
if (!city) city = "city " + Math.ceil(Math.random() * 1000);
var addCity = document.createElement("button");
addCity.setAttribute("data-value", city);
addCity.textContent = city;
addCity.addEventListener('click', e => {
console.log(`my city is: ${e.target.dataset.value}`);
})
document.getElementById("searchHistory").append(addCity);
cities.push(city);
// localStorage.setItem("searches",JSON.stringify(cities));
}
<div id='searchHistory'>
</div>
<button onclick='recentSearch()'>Make City</button>

How to add a button to run code inside LeafletJS marker?

I am trying to add a button inside a pointer which print a log to the console. This is just meant to be a test, so I can actually make the marker run a method, but I can't even get it to print text.
const marker = L.marker([latitude, longitude]).addTo(map);
const button = '<br/><button type="button">Click button</button>'
const clickbutton = document.querySelector("#click");
button1.addEventListener("click", function(event) {
console.log('This button works!');
});
marker.bindPopup(button);
When I load the page, I immediately get this error:
Uncaught (in promise) TypeError: Cannot read properties of null (reading 'addEventListener')
The console says this error is caused by
button1.addEventListener("click", function(event) {
but I'm not sure why it's null. Can anyone help me out?
You are creating the button incorrectly.
It will be right this way:
const button = document.createElement('button');
button.id = 'delete';
button.textContent = 'Delete marker';
In order to add a button to the page, you need to find the desired parent element and add the button as a child element:
// replace this id with what you need
const buttonParrentId = 'button-parrent-id';
const buttonParrent = document.getElementById(buttonParrentId);
buttonParrent.appendChild(button);
Next, you can work with the button as you need:
const marker = L.marker([latitude, longitude]).addTo(map);
button.addEventListener("click", function(event) {
console.log('This button works!');
});
marker.bindPopup(button);
Result code example:
const button = document.createElement('button');
button.id = 'delete';
button.textContent = 'Delete marker';
// replace this id with what you need
const buttonParrentId = 'button-parrent-id';
const buttonParrent = document.getElementById(buttonParrentId);
buttonParrent.appendChild(button);
const marker = L.marker([latitude, longitude]).addTo(map);
button.addEventListener("click", function(event) {
console.log('This button works!');
});
marker.bindPopup(button);
More about createElement

Remove dynamically created elements by class name Javascript

So, in plain terms I am creating a Chrome Extension that so far can only save links from the internet but not delete them. What I want to add is a "remove" button for deleting unwanted links. So far I haven't got that to work.
The buttons I want to remove are added using JavaScript. Each new block of HTML features a "remove" button but clicking that button does nothing. I have tried binding listeners to each element using a for loop but that doesn't seem to work.
The code runs without errors and I'm certain that the issue is a slight oversight but I have only just started using JavaScript so I'm lost for solutions at the moment.
I have included all the code because I don't want to leave out anything that might be imperative to finding a solution.
It starts with the code for adding a link, followed by removing a single link and then removing all links at once. Thank you all for any help, really want to get this working.
https://github.com/mmmamer/Drop Repository for the rest of the code. Mainly popup.html and popup.css.
var urlList = [];
var i = 0;
document.addEventListener('DOMContentLoaded', function() {
getUrlListAndRestoreInDom();
// event listener for the button inside popup window
document.getElementById('save').addEventListener('click', addLink);
});
function addLink() {
var url = document.getElementById("saveLink").value;
addUrlToListAndSave(url);
addUrlToDom(url);
}
function getUrlListAndRestoreInDom() {
chrome.storage.local.get({
urlList: []
}, function(data) {
urlList = data.urlList;
urlList.forEach(function(url) {
addUrlToDom(url);
});
});
}
function addUrlToDom(url) {
// change the text message
document.getElementById("saved-pages").innerHTML = "<h2>Saved pages</h2>";
var newEntry = document.createElement('li');
var newLink = document.createElement('a');
var removeButton = document.createElement('button');
removeButton.textContent = "Remove";
//removeButton.createElement('button');
removeButton.type = "button";
removeButton.className = "remove";
newLink.textContent = url;
newLink.setAttribute('href', url);
newLink.setAttribute('target', '_blank');
newEntry.appendChild(newLink)
newEntry.appendChild(removeButton);
newEntry.className = "listItem";
document.getElementById("list").appendChild(newEntry);
}
function addUrlToListAndSave(url) {
urlList.push(url);
saveUrlList();
//}
}
function saveUrlList(callback) {
chrome.storage.local.set({
urlList
}, function() {
if (typeof callback === 'function') {
//If there was no callback provided, don't try to call it.
callback();
}
});
}
// remove a single bookmark item
document.addEventListener('DOMContentLoaded', function() {
getUrlListAndRestoreInDom();
var allButtons = document.getElementsByClassName('remove');
function listenI(i) {
allButtons[i].addEventListener('click', () => removeMe(i));
}
for (var i = 0; i < allButtons.length; i++) {
listenI(i);
}
});
function removeMe(i) {
var fullList = documents.getElementsByClassName('listItem');
listItem[i].parentNode.removeChild(listItem[i]);
}
//remove all button
document.addEventListener('DOMContentLoaded', function() {
document.getElementById("remove-all").addEventListener('click', function() {
var removeList = document.getElementsByClassName("listItem");
while(removeList[0]) {
removeList[0].parentNode.removeChild(removeList[0]);
}
})
});
chrome.storage.local.get() is asynchronous. So when you try to add the event listeners to the Remove buttons, they're not in the DOM yet.
You can add the listener in the addUrlToDom() function instead. That way you'll also add the event listener when you create new buttons.
function addUrlToDom(url) {
// change the text message
document.getElementById("saved-pages").innerHTML = "<h2>Saved pages</h2>";
var newEntry = document.createElement('li');
var newLink = document.createElement('a');
var removeButton = document.createElement('button');
removeButton.textContent = "Remove";
//removeButton.createElement('button');
removeButton.type = "button";
removeButton.className = "remove";
newLink.textContent = url;
newLink.setAttribute('href', url);
newLink.setAttribute('target', '_blank');
newEntry.appendChild(newLink)
newEntry.appendChild(removeButton);
removeButton.addEventListener("click", function() {
var anchor = this.previousElementSibling;
var url = anchor.getAttribute("href");
removeUrlAndSave(url);
this.parentNode.remove();
});
newEntry.className = "listItem";
document.getElementById("list").appendChild(newEntry);
}
function removeUrlAndSave(url) {
var index = urlList.indexOf(url);
if (index != -1) {
urlList.splice(index, 1);
saveUrlList();
}
}

Why can't I assign a function to Object.prototype.click?

I know how to create dynamic elements and append them to existing ones, and how to create click events and attach them. See my snippet below
var container = document.getElementById("container");
var btn1 = document.createElement("button");
var btn2 = document.createElement("button");
btn1.innerHTML = "button 1";
btn2.innerHTML = "button 2";
btn1.onclick = function(){ console.log('button 1 clicked'); }; // this works fine
btn2.onclick = function(){ console.log('button 2 clicked'); };
container.append(btn1);
container.append(btn2);
<div id="container"></div>
I am trying to mimic jQuery's .click() behavior. (I don't want to use jQuery, I just need a shorter way of assigning click events to dynamically created elements).
What I mean, is I would like to extend Object.prototype by adding a function that accepts a function as the parameter, and all it does behind the scenes is assign it to the object's .onclick property.
However, the code runs, but no click event is triggered, and no error is reported.
var container = document.getElementById("container");
var btn1 = document.createElement("button");
var btn2 = document.createElement("button");
btn1.click(function(){ console.log('button 1 clicked'); }); // this doesn't work
btn2.click(function(){ console.log('button 2 clicked'); }); // this doesn't work
btn1.innerHTML = "button 1";
btn2.innerHTML = "button 2";
container.append(btn1);
container.append(btn2);
Object.prototype.click = function(fn) {
console.log('this function never gets executed');
this.onclick = fn;
}
<div id="container"></div>
I can tell that my extension of Object.prototype.click has not been executed since the console.log() never happens.
Is it because Object.prototype.click is reserved? If so, why am I not being able to override its definition?
What am I doing wrong?
There are two issues. First, you should assign to the prototype before you try calling btn1.click(), else the native .click() will be called. (The native .click() method of an element programatically triggers a click event on that element.)
The other problem is that btn1 is an element, not just an object, and HTMLElements have a click property on their prototype. So, even if you assign to Object.prototype.click, HTMLElement.prototype.click will be seen sooner in the prototype chain, and so your Object.prototype.click will be ignored. You'll have to either overwrite HTMLElement.prototype.click or HTMLButtonElement.click:
var container = document.getElementById("container");
var btn1 = document.createElement("button");
var btn2 = document.createElement("button");
HTMLElement.prototype.click = function(fn) {
console.log('setting up click event');
this.onclick = fn;
}
btn1.click(function(){ console.log('button 1 clicked'); });
btn2.click(function(){ console.log('button 2 clicked'); });
btn1.innerHTML = "button 1";
btn2.innerHTML = "button 2";
container.append(btn1);
container.append(btn2);
<div id="container"></div>
But mutating the built-in objects like this isn't very good practice and can lead to things breaking (such as if a library assumes that .click() will trigger the normal HTMLElement.prototype.click function) - you might consider assigning click property directly to the instance, rather than to the prototype:
var container = document.getElementById("container");
function myCreateElement(type) {
const elm = document.createElement(type);
elm.click = function(fn) {
console.log('setting up click event');
this.onclick = fn;
}
return elm;
}
var btn1 = myCreateElement("button");
var btn2 = myCreateElement("button");
btn1.click(function(){ console.log('button 1 clicked'); });
btn2.click(function(){ console.log('button 2 clicked'); });
btn1.innerHTML = "button 1";
btn2.innerHTML = "button 2";
container.append(btn1);
container.append(btn2);
<div id="container"></div>

I need to access event context AND object context in event handler

I've this piece of code:
function ActivityDialog(_divId, _title) {
function addButton() {
var buttonElement = document.createElement('input');
buttonElement.setAttribute('type','button');
buttonElement.setAttribute('class','button');
buttonElement.setAttribute('id','updateButton-' + id););
buttonElement.onclick = this.updateAction;
};
function updateAction() {
var buttonId = this.id; // correct: this is the Button
this.sendUpdateRequest(stringUrl); // not defined: Need to reference the current ActivityDialog!!!
};
function sendUpdateRequest(url) {
// something...
};
}
As you can see the problem is when I call function sendUpdateRequest; how can I, at the same time, retrieve button infos and call a function?
You might try this...
function ActivityDialog(_divId, _title) {
// Store the ActivityDialog context
var self = this;
function addButton() {
var buttonElement = document.createElement('input');
buttonElement.setAttribute('type','button');
buttonElement.setAttribute('class','button');
buttonElement.setAttribute('id','updateButton-' + id););
buttonElement.onclick = this.updateAction;
};
function updateAction() {
var buttonId = this.id;
self.sendUpdateRequest(stringUrl); // <---------------------
};
function sendUpdateRequest(url) {
// something...
};
}
Because your using updateAction as a event handler, you correctly see that this will be the button that generates the event. Storing the initial context of the ActivityDialog will allow you to maintain access to it even within event handlers.

Categories

Resources