Change InnerHTML based on anchor click - javascript

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.

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 = "".

Removing an array element by clicking an HTML <li>

So I'm doing a playlist manager for youtube (using the ytb api) and for the graphic part I'm doing, such as youtube has, a list of every thumbnail there is in a given playlist. I use an HTML 'ul' and add every thumbnail as a 'li'.
Everything is working fine but id like to add a feature so the user could click on one of the thumbnails to remove it from the playlist.
First, let me explain how the important part is coded.
I use an array as a queue to stock every video ID that will be played (this is the playlist) :
var queue = []
And for the thumbnail list I use this function :
function refreshThumbnailsQueue() {
var thumbnailsUl = document.getElementById('thumbnailslist');
while(thumbnailsUl.firstChild) {
thumbnailsUl.removeChild(thumbnailsUl.firstChild );
}
for (var i = 0; i <= queue.length - 1; i++) {
var thumbnail = 'http://img.youtube.com/vi/' + queue[i] + '/maxresdefault.jpg';
var newLi = document.createElement('li');
newLi.className = 'thumbnailLi';
newLi.onclick = function() {
removeFromQueue();
}
var newImg = document.createElement('img');
newImg.className = 'thumbnailImg';
newImg.src = thumbnail;
newLi.appendChild(newImg);
thumbnailsUl.appendChild(newLi);
}
}
So I'm just removing every child the ul has and then filling it with every thumbnail of the video IDs there are in my queue var.
As you can see, there is a removeFromQueue() function called with an onclick event on each li in the code, and this is what I try to code.
Basicaly, if you click the third li, it should remove the third element of my queue var.
If you have any ideas, please let me know. (and BTW sorry for the mistakes English isn't my main language)
Thanks!
Note : I dont want to use jQuery.
If jQuery is an option, you can simply do the following :
$( "li" ).click(function(){
$( this ).remove();
})
As simple as that. If you want more information, I'll update my answer.
You can also visit this page for plain old javascript. Here is the important part :
var elem = document.getElementById("myDiv");
elem.parentNode.removeChild(elem);
As for the index of the li element
When you insert the list item in the DOM, you also set it's ID like this :
function refreshThumbnailsQueue() {
...
for (var i = 0; i <= queue.length - 1; i++) {
...
// Create the li.
var newLi = document.createElement('li');
newLi.id = "song-" + i;
// Create the onclick listening
li.onclick = function(){
// Remove from DOM.
var elem = document.getElementById(this.id);
elem.parentNode.removeChild(elem);
// We keep only the integer (index)
// In this example, '5' cuts away the "song-".
var index = parseInt((this.id+"").substring(5));
// Then, we remove it from the list.
YourProgram.removeIndex(index);
}
...
thumbnailsUl.appendChild(newLi);
}
}
This way, you know what it's index is.
Hope it helps.
Pass the index of the element to remove to the removeFromQueue(), like removeFromQueue(i). Then remove the item from queue.
function removeFromQueue(index) {
queue.splice(index, 1)
refreshThumbnailsQueue()
}

Formatting a href link with appendChild, setAttribute, etc

I am attempting to populate a list with href links via javascript.
Here is an example of the html I would like to create:
<li> Complete blood count</li>
Where "#modal-one" displays a pop up.
I have used the following and several other iterations to try and create this dynamically:
<script>
var listItem = [];
function createTestList() {
var tests = results.tests; //an array to tests to populate list
var i;
var j;
for (i = 0; i < tests.length ; i++ ){
listItem[i] = document.createElement("li");
var node = document.createTextNode(tests[i].name);
listItem[i].appendChild(node);
listItem[i].setAttribute("href", "#modal-one");
addOnClick(i);
//var element = document.getElementById("div1");
//element.appendChild(listItem[i]);
document.body.appendChild(listItem[i]);
console.log(listItem[i]);
};
};
function addOnClick(j) { //this is separate to handle the closure issue
listItem[j].onclick = function() {loadModal(j)};
};
</script>
However, this code (and several others) produce:
<li href='#modal-one'>Complete Blood Count</li> //note missing <a>...</a>
It appears there are several ways to achieve this, but nothing seems to work for me...
You are never actually adding in an anchor tag. You are creating a list-item (li), but you are adding an href to that list-item rather than adding an anchor node to it with that href. As such, the browser just thinks you have a list-item with an href attribute.
Consider using the following instead:
<script>
var listItem = [];
function createTestList() {
var tests = results.tests; //an array to tests to populate list
var i;
var j; // Never actually used in function. Consider omitting
for (i = 0; i < tests.length ; i++ ){
// create the list item
listItem[i] = document.createElement("li");
// Create the anchor with text
var anchor = document.createElement("a");
var node = document.createTextNode(tests[i].name);
anchor.appendChild(node);
anchor.setAttribute("href", "#modal-one");
// Set the onclick action
addOnClick(i, anchor);
// Add the anchor to the page
listItem[i].appendChild(anchor);
document.body.appendChild(listItem[i]);
console.log(listItem[i]);
};
};
// Modified "addOnClick" to include the anchor that needs the onclick
function addOnClick(j, anch) { //this is separate to handle the closure issue
anch.onclick = function() {loadModal(j)};
};
</script>
A couple things to note:
I have modified your addOnClick() function because it is the anchor element that needs the onclick, not the list item.
I have added in the creation of an anchor element rather than simply creating a list item and adding the href to that.
I do not see creating a element, change code to:
var aNode=document.createElement("a");
aNode.innerText=tests[i].name;
aNode.setAttribute("href", "#modal-one");
listItem[i].appendChild(aNode);
You can change also click method, to use it on a not on li
function addOnClick(j) {
listItem[j].querySelector("a").addEventListener("click",function(e) {
e.preventDefault();//this prevent for going to hash in href
loadModal(j);
});
};
Okay. I missed the anchor tag. My bad...
Spencer's answer came close, but I had to make few changes to get it work in my instance.
The final working code (and honestly I am not sure why it works) is:
<script>
var listItem = [];
function createTestList() {
var tests = results.tests;
var i;
//var j;
for (i = 0; i < tests.length ; i++ ){
// create the list item
listItem[i] = document.createElement("li");
// Create the anchor with text
var anchor = document.createElement("a");
anchor.setAttribute("href", "#modal-one");
var node = document.createTextNode(tests[i].name);
anchor.appendChild(node);
// Set the onclick action
addOnClick(i);
// Add the anchor to the page
listItem[i].appendChild(anchor);
document.getElementById("demo").appendChild(listItem[i]); //added the list to a separate <div> rather than body. It works fine like this.
console.log(listItem[i]);
};
};
function addOnClick(j) { //this is separate to handle the closure issue
//didn't need the additional code beyond this
listItem[j].onclick = function() {loadModal(j)};
};
</script>
Thanks to all and Spencer thanks for the thoroughly commented code. It helps!!!

Javascript + DOM - links within same page

I have a existing page with several entries(divs), and I loop trough all of them to fetch the wanted content(headers) to create a list of links.
In the process I assign each header a unique ID, but I can't seem to get my list of links to "connect" to the specific entries.
Javascript:
var entries = document.getElementsByClassName('entry');
var ul = document.createElement('ul');
for (var i = 0; i < entries.length; i++) {
var li = document.createElement('li');
var heading = entries[i].getElementsByTagName('h2')[0];
var addId = heading.setAttribute("id", "#entry" + i);
var x = heading.getAttribute("id");
var headingText = document.createTextNode(heading.firstChild.nodeValue);
var link = document.createElement('a');
link.setAttribute("href", x);
link.appendChild(headingText);
li.appendChild(link);
ul.appendChild(li);
}
var target = document.getElementById('newdiv');
target.appendChild(ul);
What am I missing, or doing wrong?
When I hover over my list with links, they show the link as supposed - but nothing happens when I click it. If I inspect the DOM I can also see that all of the headers got assigned a unique ID.
Remove # from :
var addId = heading.setAttribute("id", "entry" + i);//("id", "#entry" + i)
and Add # to :
link.setAttribute("href", "#"+x);//("href",x)

When using this .js 2 times on a single page it only works in the one instance

This script creates menu tabs above a text area. The script works if use only once on a page, I however need to use it twice on a single page, to create 2 text areas, each with a menu above them. As soon as I use it twice only one instance works. Any suggestions.
window.onload=function() {
// get tab container
var container = document.getElementById("tabContainer");
// set current tab
var navitem = container.querySelector(".tabs ul li");
//store which tab we are on
var ident = navitem.id.split("_")[1];
navitem.parentNode.setAttribute("data-current",ident);
//set current tab with class of activetabheader
navitem.setAttribute("class","tabActiveHeader");
//hide two tab contents we don't need
var pages = container.querySelectorAll(".tabpage");
for (var i = 1; i < pages.length; i++) {
pages[i].style.display="none";
}
//this adds click event to tabs
var tabs = container.querySelectorAll(".tabs ul li");
for (var i = 0; i < tabs.length; i++) {
tabs[i].onclick=displayPage;
}
}
// on click of one of tabs
function displayPage() {
var current = this.parentNode.getAttribute("data-current");
//remove class of activetabheader and hide old contents
document.getElementById("tabHeader_" + current).removeAttribute("class");
document.getElementById("tabpage_" + current).style.display="none";
var ident = this.id.split("_")[1];
//add class of activetabheader to new active tab and show contents
this.setAttribute("class","tabActiveHeader");
document.getElementById("tabpage_" + ident).style.display="block";
this.parentNode.setAttribute("data-current",ident);
}
Havn't found solution yet, but FYI, you originally marked this as jQuery, if it had been jquery, you could easily break a few lines of that code and write it as simple as: (depending on version)
function displayPage(e) {
var current = $(this).parent().attr("data-current");
$("#tabHeader_" + current).removeClass("tabActiveHeader")
$("#tabpage_" + current).hide();
var ident = this.id.split("_")[1];
$(this).addClass("tabActiveHeader");
$("#tabpage_" + ident).show();
$(this).parent().attr({ 'data-current': ident })
}
$(function() {
var container = $("#tabContainer"),
navitem = container.find((".tabs ul li")).first(),
ident = navitem[0].id.split("_")[1];
navitem.addClass("tabActiveHeader").parent().attr({ 'data-current': ident });
$(".tabpage").filter(function(i) { return i>0; }).hide();
// OR
// $(".tabpage:not(:first-child)").hide();
$(".tabs ul li").on("click", displayPage)
});​
See WORKING Example of the previous jQUERY in this jsFiddle
ALSO, Have you look at jQueryUI.Tabs?
Instead of hard-setting window.onload—which replaces the last-set handler with the new one—use the following code that registers an arbitrary number of event handlers for the same event on the same object:
window.addEventListener('load',function(){
// Your code here
},false);
More can be read about element.addEventListener and specifically IE Support
This will not work for older versions of IE; if you need this support, I strongly recommend using a cross-browser library like jQuery. You originally tagged your question as relating to jQuery, but there is no jQuery used in your code.

Categories

Resources