I need to pass a reference to current element that is being clicked in href tag.
Consider this code which goes in a loop when creating a table
td=document.createElement("td");
td.innerHTML='click me';
But this doesn't work because it points to the browser window so when I am setting it to something the whole page replaced the value I am setting it to. So how do I pass the reference to <a> object into some_function() ?
where some_function() is declared like:
function some_function(clicked_object,param2,param3) {
clicked_object.style.backgroundColor="red"
}
Here's a full fledged solution that avoids inline code:
for (var i = 0; i < 10; i++) {
// create elements
let td = document.createElement("td");
let a = document.createElement("a");
a.innerHTML = `cell #${i}`;
a.href = ""; // we need this so <a> appears as link
// set click handler
a.addEventListener("click", some_function);
// add some data
a.dataset.rowNumber = 1;
a.dataset.extra = i * 2 + 7;
td.appendChild(a);
row.appendChild(td);
}
function some_function(e) {
e.preventDefault(); // stop default event handling
let clicked_object = e.target; // get clicked element from event
clicked_object.style.backgroundColor = "red";
console.log("param:", clicked_object.dataset.extra);
}
<table>
<tbody>
<tr id="row"></tr>
</tbody>
</table>
Edit: added data to elements
Related
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.
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!!!
The code below makes a Div for every object it finds in an array. It then adds a header, a paragraph, an image, and an anchor.
The div's actually look like rectangles on top of one another. What I would like to do is add an onclick attribute to the divs based on the keys within my objects ( coffeShops[i].menu). When I do so though, clicking just doesn't do anything and i get this error message in console
"Uncaught TypeError: Cannot read property 'menu' of undefined"
This only happens when I try window.open with the object key coffeShops[i].menu. If I swap that out with "http://www.google.com" it works just fine. Also, the links from that variable show up in the console just fine. So I know it's getting the data from the object just fine. But for some reason it doesn't want to open from the div.
FYI I'm extremely new to this so apologies if the explanation doesn't make sense.
var containerDiv = document.getElementById("container");
console.log(containerDiv);
for (var i = 0; i < coffeeShops.length; i++){
var launchMenu = function(){
window.open(coffeeShops[i].menu);
}
console.log(coffeeShops[i].menu);
var coffeeShopDiv = document.createElement("div");
coffeeShopDiv.className = "coffeeShop";
coffeeShopDiv.onclick = launchMenu;
containerDiv.appendChild(coffeeShopDiv);
var coffeeShopImage = document.createElement("img");
coffeeShopImage.src = coffeeShops[i].image;
coffeeShopImage.className = "coffeeImage";
coffeeShopDiv.appendChild(coffeeShopImage);
var coffeeShopHeader = document.createElement("h1");
coffeeShopHeader.className = "coffeeHeader"
coffeeShopHeader.innerHTML = coffeeShops[i].name;
coffeeShopDiv.appendChild(coffeeShopHeader);
var coffeeShopPar = document.createElement("p");
coffeeShopPar.className = "coffeeDescription"
coffeeShopPar.innerHTML = coffeeShops[i].description;
coffeeShopDiv.appendChild(coffeeShopPar);
var coffeeMenu = document.createElement("a");
coffeeMenu.href = coffeeShops[i].menu;
coffeeMenu.innerHTML = "MENU"
coffeeShopDiv.appendChild(coffeeMenu);
};
EDITED: in light of comment
It looks like you need to separate the function which opens the new window from the code which generates page items. By slightly restructuring your code this can be achieved by using the element.addEventListener() method.
/* place the 'launchMenu' outside of
the for-loop so it can be accessed
by each of the target elements */
function launchMenu(event){
/* get the class attribte of
the clicked element */
var clickedClass = event.target.className;
var targetElement,
link;
/* is the clicked element the containing div? */
if (clickClass !== 'coffeeShop') {
/* nope */
targetElement = event.target.parentNode;
} else {
/* yep */
targetElement = event.target;
}
/* get 'data-url' of target */
link = targetElement.getAttribute('data-url');
/* open the new window */
window.open(link);
}
/* elsewhere: create elements as before */
for (var i = 0; i < coffeeShops.length; i++){
var coffeeShopDiv = document.createElement("div");
coffeeShopDiv.className = "coffeeShop";
/* add 'data-' attribute to target div */
coffeeShopDiv.setAttribute('data-url', coffeeShops[i].menu);
containerDiv.appendChild(coffeeShopDiv);
var coffeeShopImage = document.createElement("img");
coffeeShopImage.src = coffeeShops[i].image;
coffeeShopImage.className = "coffeeImage";
coffeeShopDiv.appendChild(coffeeShopImage);
var coffeeShopHeader = document.createElement("h1");
coffeeShopHeader.className = "coffeeHeader"
coffeeShopHeader.innerHTML = coffeeShops[i].name;
coffeeShopDiv.appendChild(coffeeShopHeader);
var coffeeShopPar = document.createElement("p");
coffeeShopPar.className = "coffeeDescription"
coffeeShopPar.innerHTML = coffeeShops[i].description;
coffeeShopDiv.appendChild(coffeeShopPar);
var coffeeMenu = document.createElement("a");
coffeeMenu.className = 'coffeeMenu';
coffeeMenu.innerHTML = "MENU"
coffeeShopDiv.appendChild(coffeeMenu);
/* attach an eventListener to each
created '.coffeeShopDiv' element */
coffeeMenu.addEventListener(
'click', launchMenu, false
);
};
The target element (coffeeShopDiv) now contains a url-reference in its 'data-url' attriubte and has an event listener assigned.
When the target element, or any of her child elements, are clicked the launchMenu() function will be invoked. This function checks which element was clicked by comparing the className attribute to the class name of 'coffeeShopDiv' - such that if the class name of the clicked element is not 'coffeeShop' the targetElement variable is assigned to the clicked elements parent Node (that is, 'coffeShopDiv').
The 'data-url' reference is obtained and used in window.open().
Also see:
Using data-* attributes
Event.target
Quriksmode: Introduction to Events
This StackOverflow answer about using
window.open()
I'm really new to JavaScript but I can't find out why this program won't work.
I want when I click the dynamically created button which is situated in a cell in my dynamically created table to get the rowindex of the row in which the button is situated.
Thanks in advance - here is my code:
<html>
<head>
<script>
function whichrow(obj) {
var par = obj.parentNode;
while(par.nodeName.toLowerCase()! = 'tr') {
par = par.parentNode;
}
alert(par.rowIndex);
}
</script>
</head>
<body>
<script>
mybody = document.getElementsByTagName("body")[0];
mytable = document.createElement("table");
mytablebody = document.createElement("tbody");
for(var i = 0; i<5; i++) {
mycurrent_row = document.createElement("tr");
mycurrent_row.id = "row"+i;
for(var j = 0; j<4; j++) {
mycurrentcell = document.createElement("td");
currenttext = document.createTextNode("Row" + i + "Column" + j);
mycurrentcell.appendChild(currenttext);
mycurrent_row.appendChild(mycurrentcell);
}
mybutoncell = document.createElement("td");
but = document.createElement("button");
mybutoncell.appendChild(but);
mycurrent_row.appendChild(mybutoncell);
mytablebody.appendChild(mycurrent_row);
but.onClick = whichrow(this);
}
mytable.appendChild(mytablebody);
mybody.appendChild(mytable);
mytable.setAttribute("border", "2");
</script>
</body>
</html>
Ok, so a few points to note here.
In the javascript eventing system, the system calls your callback with its own event object containing different properties according to what happened.
So, here are the mistakes:
When you're assigning to the event handler, when you say but.onclick = whichrow(this) you're setting but.onclick to the result of whichrow, which is undefined since you're not returning anything anyway. It should be but.onclick = whichrow; which will call whichrow when the user clicks your button. The parameter passed is a MouseEvent object. The link I've supplied should serve as a good start to read up on what kind of properties are available to you.
I have to check, since I use el.addEventListeners a lot, but onclick needs to be in lower case, not camelCase like you've done.
Inside the event callback, this usually refers to the element that was clicked, so you should use that.
There is no rowIndex property.
Now, trying to find a solution to your problem. rowIndex can be gleaned by traversing the dom. I'm not sure what purpose this will serve since you're creating the DOM by hand anyway and know the rowIndex already, but if it were unknown, here's what I would do
function whichRow(e) {
// here this should be the button.
var curRow = this.parentElement.parentElement,
rowIndex = 0;
while(curRow) {
curRow = curRow.previousElementChild;
rowIndex++;
}
return rowIndex;
}
I'm writing this off the top of my head, but the point is to give the main idea. In the above snippet, I've taken the parent of the parent of the button, since here's the approximate markup of the button section:
<tr>
<td>
<button></button>
</td>
</tr>
so, the parentElement of the parentElement of the button element should give you the <tr>. Then we'll traverse backwards till we don't have any previous elements, counting as we go. Once the previous element is null, return the count.
The obj you are passing to whichrow() is a button, which I assume inside a TD. So your while loop will exit in its first iteration itself, resulting in par holding a TD - which does not have a property named rowIndex
The code below will add element once user clicks addmore link.
The problem arrives when the user clicks the remove link.
I have something like these on my code
<script language="JavaScript">
var count=1;
function addmore() {
alert(count);
var printme = "<table id='table"+count+"'><tr><td><a href='#' onclick='remove(count)'>remove</a></td></tr></table";
//(other code here)...
count++;
}
function remove(y) {
alert(y)
var tab = 'table'+y;
document.getElementById(tab).style.display = "none";
}
</script>
I used the alert here so I can easily monitor the value of count it gives.
What happens here is that the value of 'y' (on remove function) always the same, which is the last value of count in the loop.
For example I click the link addmore 3 times, therefore the last value of my 'count=4'.
And let say I wanted to remove the 3rd element which at this point when i clicked the remove link, it must have pass argument like this remove(3). But what happens here is whatever element i clicked it seems like it always passing argument this way remove(4)
That's because you have count as a global variable.
Try .....onclick='remove("+count+")'.... to sort of "lock in" the value.
Please try this:
var printme = "<table id='table"+count+"'><tr><td><a href='#' onclick='remove("+count+")'>remove</a></td></tr></table";
also try following line remove function:
document.getElementById(""+tab+"").style.display = "none";
All previous answers are correct, onclick refers to the current variable count when remove is called.
When you generate the text for the table you use the value of count as it is then:
onclick='remove('+count+')...
You can leave out the id's and count altogether using this:
onclick='remove(this.parentElement.parentElement.parentElement);'...
function remove(elementToRemove){
elementToRemove.parentElement.removeChild(elementToRemove);
}
maybe just onclick='remove('+count+')'
You can do something like
<html>
<head>
<script type="text/javascript">
var count=1;
function addmore() {
var id = 'table' + count;
var table = document.createElement('table');
table.setAttribute('id', id);
var tr = document.createElement('tr');
var td = document.createElement('td');
var a = document.createElement('a');
a.setAttribute('href', '#');
a.appendChild(document.createTextNode('remove ' + id));
a.onclick = function() {
table.style.display = 'none';
document.body.removeChild(table);
};
td.appendChild(a);
tr.appendChild(td);
table.appendChild(tr);
document.body.appendChild(table);
count++;
}
</script>
</head>
<body>
Add Table
</body>
</html>
With table reference and onclick defined like this you don't need id