I'm trying to build a script that detects the particular <span> the user clicks on and outputs the value of the contents of that clicked span.
My HTML looks like this:
<div id="span-container">
<span>Lorem</span>
<span>Ipsum</span>
<span>Something...</span>
<span>Something...</span>
<span>Amet</span>
</div>
And my Javascript looks like this:
div = document.getElementById("span-container");
spans = div.getElementsByTagName("span");
for(var i = 0; i < spans.length; i++) {
spans[i].onclick = function() {
alert(spans[i].innerHTML);
}
}
Attempting to run this code results in a Cannot read property 'innerHTML' of undefined error.
I'm sure giving each span an ID that correlates to its contents like <span id="lorem">Lorem</span> would work, but I'm optimistic that a more elegant solution exists.
I'd also like to avoid using jQuery if possible.
Thanks!
Use event delegation:
var div = document.getElementById('span-container');
div.addEventListener('click', function(e) {
var target = e.target;
if(target.nodeName == 'SPAN') {
alert(target.innerHTML);
}
});
Wrapping it
The problem is, i has changed by the time the user click on it. Use a self-executing function or eventListener
div = document.getElementById("span-container");
spans = div.getElementsByTagName("span");
for(var i = 0; i < spans.length; i++) {
(function (j) {
spans[j].onclick = function() {
alert(spans[j].innerHTML);
}
}(i));
}
div = document.getElementById("span-container");
spans = div.getElementsByTagName("span");
for(var i = 0; i < spans.length; i++) {
(function (j) { // Receives as j
spans[j].onclick = function() {
alert(spans[j].innerHTML);
}
}(i)); // Passes in i
}
<div id="span-container">
<span>Lorem</span>
<span>Ipsum</span>
<span>Something...</span>
<span>Something...</span>
<span>Amet</span>
</div>
Using this
this will refer to the element clicked and is probably the best way to do this:
div = document.getElementById("span-container");
spans = div.getElementsByTagName("span");
for(var i = 0; i < spans.length; i++) {
spans[i].onclick = function() {
alert(this.innerHTML);
}
}
div = document.getElementById("span-container");
spans = div.getElementsByTagName("span");
for(var i = 0; i < spans.length; i++) {
spans[i].onclick = function() {
alert(this.innerHTML);
}
}
<div id="span-container">
<span>Lorem</span>
<span>Ipsum</span>
<span>Something...</span>
<span>Something...</span>
<span>Amet</span>
</div>
The problem here is the wrong use of a closure variable in a loop
But I think in this case you can use addEventListener
div = document.getElementById("span-container");
spans = div.getElementsByTagName("span");
function spanClickHandler() {
alert(this.innerHTML);
}
for (var i = 0; i < spans.length; i++) {
spans[i].addEventListener('click', spanClickHandler, false);
}
<div id="span-container"> <span>Lorem</span>
<span>Ipsum</span>
<span>Something...</span>
<span>Something...</span>
<span>Amet</span>
</div>
or just use this.innerHTML as this inside the event handler refers to the span element
spans[i].onclick = function () {
alert(this.innerHTML);
}
JavaScript closure inside loops – simple practical example
You can use this for the current element.
Try this code:
div = document.getElementById("span-container");
spans = div.getElementsByTagName("span");
for(var i = 0; i < spans.length; i++) {
spans[i].onclick = function() {
alert(this.innerHTML);
}
}
Related
I have 2 divs by class name tag which contain p,span tags . So when I trigger an onclick event on a div they should log or show the content of p, span tags.
But when I am doing that it gives all the content of say 2 divs that I have in my markup.
How do I go by that when I click on that particular div the content of p, span tags of that clicked div should be displayed and not of all the p, span tags.
var tag = document.getElementsByClassName("tag");
var pTag = document.querySelectorAll("P");
var sTag = document.querySelectorAll("SPAN");
for (var i = 0; i < tag.length; i++) {
tag[i].onclick = function() {
for (var j = 0; j < pTag.length; j++) {
console.log(pTag[j].innerHTML);
}
}
}
<div class="tag">
<p>Head Text-1</p>
<span>10</span>
</div>
<div class="tag">
<p>Head Text-2</p>
<span>20</span>
</div>
onclick should be inside for loop. Also to get the text you should use textContent instead of innerHTML:
var tag = document.getElementsByClassName("tag");
var pTag = document.querySelectorAll("P");
var sTag = document.querySelectorAll("SPAN");
for (var i = 0; i < tag.length; i++) {
for (var j = 0; j < pTag.length; j++) {
tag[i].onclick = function() {
console.log(this.textContent);
}
}
}
<div class="tag">
<p>Head Text-1</p>
<span>10</span>
</div>
<div class="tag">
<p>Head Text-2</p>
<span>20</span>
</div>
this will solve your issue
var tag = document.getElementsByClassName("tag");
var pTag = document.querySelectorAll("P");
var sTag = document.querySelectorAll("SPAN");
function showContent(event){
console.log(event.lastElementChild.innerText);
}
<div class="tag" onclick="showContent(this)">
<p>Head Text-1</p>
<span>10</span>
</div>
<div class="tag" onclick="showContent(this)">
<p>Head Text-2</p>
<span>20</span>
</div>
What you want is to get your tag's textContent, But instead, your tag.onclick show the entire document's p elements (which is your pTag in your question).
Following is a sample how you can select the children element's p and span of the clicked .tag
var tags = document.getElementsByClassName("tag");
for (var i = 0; i < tags.length; i++) {
tags[i].onclick = function () {
var self = this,
childParagraphs = [].filter.call(document.querySelectorAll("p"), function(elem) {
return elem.parentNode === self;
}),
childSpans = [].filter.call(document.querySelectorAll("span"), function(elem) {
return elem.parentNode === self;
});
for (var j = 0; j < childParagraphs.length; j++) {
console.log('childParagraph: ', childParagraphs[j].innerHTML);
}
for (var j = 0; j < childSpans.length; j++) {
console.log('childSpan: ', childSpans[j].innerHTML);
}
}
}
<div class="tag">
<p>Head Text-1</p>
<span>10</span>
</div>
<div class="tag">
<p>Head Text-2</p>
<span>20</span>
</div>
Or, if you really just need the whole text of the entire .tag, you can use #Mamun answer by using textContent.
Inside my php while loop I output a div with id divborder, and class div-border
Inside that div i have another div with id title
<div id='divborder' class='div-border'>
<div id='Title'>This is Title</div> <br/> video elements
</div>
I have a JavaScript function that get called when the video ends
for (var i = 0; i < videos.length; i++) {
videos[i].addEventListener("ended", function(event)
{
var divBoader2 = document.getElementsByClassName("divborder")[3];
divBoader2.style.borderColor = "#b1ff99";
}
My Question is how do i change the border color of the div and the title of second div?
I can do it like this:
var divBoader2 = document.getElementsByClassName("divborder")[3];
divBoader2.style.borderColor = "#b1ff99";
which works but its not dynamic
Save the value of value at i in another variable declared with let
for (var i = 0; i < videos.length; i++) {
let index = i; //save the value as let so that its binding stays
videos[i].addEventListener("ended", function(event)
{
var divBoader = document.querySelectorAll("div-border")[index];
divBoader.style.borderColor = "#b1ff99";
}
}
Or if the video elements are within the div-border, then use closest
for (var i = 0; i < videos.length; i++) {
videos[i].addEventListener("ended", function(event)
{
var divBoader = event.currentTarget.closest(".div-border");
divBoader.style.borderColor = "#b1ff99";
}
}
A little less verbose code
[...videos].forEach( s => s.closest( ".div-border" ).style.color = "#b1ff99" )
Try this,
Give class name div-border instead of divborder
for (var i = 0; i < videos.length; i++) {
videos[i].addEventListener("ended", function(event)
{
var divBoader2 = document.getElementsByClassName("div-border")[3];
divBoader2.style.borderColor = "#b1ff99";
}
What you need is probably a videos[i].parentNode instead of document.getElementsByClassName("div-border")[3] (see https://developer.mozilla.org/en-US/docs/Web/API/Node/parentNode)
I am looking to create a very simple functionality of clicking on a menu tab and it changes color to let you know what page you are on. I am a novice so please take it easy on me...lol
/Menu in php header file/
<ul class="tabs" id="tabs">
<li class="selected">Home</li>
<li class="inactive">Bio</li>
<li class="inactive">Photo</li>
<li class="inactive">Thank</li>
<li class="inactive">Contact</li>
</ul>
/*This is the JavaScript file*/
window.onload = initPage;
function initPage() {
var tabs = document.getElementById("tabs").getElementsByTagName("li");
for (var i=0; i<tabs.length; i++){
var links = tabs[i];
links.onclick = tabClicked;
}
}
function tabClicked(){
var tabId = this.id;
document.getElementById(tabId).classList.toggle("selected");
var tabs = document.getElementById("tabs").getElementsByTagName("li");
for (var i=0; i < tabs.length; i++){
var currentTab = tabs[i];
if (currentTab.id !== tabId){
currentTab.class = "selected";
} else {
currentTab.class = "inactive";
}
}
}
element.setAttribute("class", "className");
You are using ids in your code but you don't have provided it in your markup. so give ids to li elements and try this.
function tabClicked(){
var tabId = this.id;
document.getElementById(tabId).classList.toggle("selected");
var tabs = document.getElementById("tabs").getElementsByTagName("li");
for (var i=0; i < tabs.length; i++){
var currentTab = tabs[i];
if (currentTab.id !== tabId){
currentTab.className = "inactive";
} else {
currentTab.className= "selected";
}
}
}
JS Fiddle Demo
Store a reference to each of the list items.
Create a variable to keep track of the current tab.
In an onclick function for each element (or you could use one onclick and just use some conditions), change the class attribute of the element by using the setAttribute() method.
Like this:
function onFirstTabClick() {
clearSelected();
tabVariable1.setAttribute("class","some-new-class");
}
function() clearSelected() {
switch(currentSelectedTrackerVariable) {
case 1: tabVariable1.setAttribute("class","some-new-class");
break;
// Do this for the amount of tabs that you have.
}
}
Working FIDDLE Demo
There is no need to define functions globally. Write all them in one package. The code below, works correctly with your HTML markup.
<script>
window.onload = function () {
var tab = document.getElementById('tabs');
var lis = tab.getElementsByTagName('li');
for (var i = 0, l = lis.length; i < l; i++) {
lis[i].onclick = function () {
for (var j = 0; j < l; j++) {
lis[j]["className"] = "inactive";
}
this["className"] = "selected";
};
}
};
</script>
If you use jQuery, then tabClicked can run:
jQuery('.selected').removeClass('selected').addClass('inactive');
jQuery(this).removeClass('inactive').addClass('selected');
I amd working with hiding and showing divs, which have different contents. When i click on a link, i want a div to be shown. But when i click on another link, i want the new content to replace the previous one. Right now, it falls under it instead of replacing it. Any solution?
Javascript
function show(){
var links = {
link1: "content1",
link2: "content2",
link3: "content3",
link4: "content4"
};
var id = event.target.id;
var a = document.getElementsByTagName("a");
document.getElementById(links[id]).style.visibility = 'visible';
}
function init(){
var divs = document.getElementsByTagName("div");
for (i = 0; i < divs.length; i++) {
if (divs[i].className == "div") {
divs[i].style.visibility = 'hidden';
}
}
var a = document.getElementsByTagName("a");
for(i = 0; i < a.length; i++){
a[i].onclick = show;
}
}
window.onload = init;
You need to run the block of code that hides them all before showing the one you want, every time.
Make this:
function hideAll() {
var divs = document.getElementsByTagName("div");
for (i = 0; i < divs.length; i++) {
if (divs[i].className == "div") {
divs[i].style.visibility = 'hidden';
}
}
Remove this code from init() and replace it with a call to hideAll() and add a call to hideAll() at the beginning of show().
I am looping through a list of links. I can correctly get the title attribute, and want it displayed onclick. When the page is loaded and when I click on a link, all of the link titles are alerted one by one. What am I doing wrong?
function prepareShowElement () {
var nav = document.getElementById('nav');
var links = nav.getElementsByTagName('a');
for (var i = 0; i < links.length; i++) {
links[i].onclick = alert(links[i].title);
}
}
What you were doing was actually running the alert function.
enclosing the whole thing in an anonymous function will only run it when it is clicked
for (var i = 0; i < links.length; i++) {
links[i].onclick = function () {
alert(this.title);
}
}
You are assigning the onclick to the return value of alert(links[i].title); which doesn't make any sense, since onclick is supposed to be a function.
What you want instead is somethig like onclick = function(){ alert('Hi'); };
But
Since you are using a variable i in that loop you need to create a local copy of it
onclick = function(){ alert(links[i].title); }; would just use the outer scope i and all your links would alert the same message.
To fix this you need to write a function that localizes i and returns a new function specific to each link's own onclick:
onclick = (function(i){ return function(e){ alert(links[i].title); }; })(i);
Final result:
function prepareShowElement () {
var nav = document.getElementById('nav');
var links = nav.getElementsByTagName('a');
for (var i = 0; i < links.length; i++) {
links[i].onclick = (function(i){ return function(e){ alert(links[i].title); }; })(i);
}
}
You can use jquery. To display title of the link on click.
$("#nav a").click(function() {
var title = $(this).attr('title');
alert(title);
});
links.forEach(function(link) {
link.onclick = function(event) {
alert(link.title);
};
}
Also note that your original solution suffered from this problem:
JavaScript closure inside loops – simple practical example
By passing in our iteration variable into a closure, we get to keep it. If we wrote the above using a for-loop, it would look like this:
// machinery needed to get the same effect as above
for (var i = 0; i < links.length; i++) {
(function(link){
link.onclick = function(event) {
alert(link.title);
}
})(links[i])
}
or
// machinery needed to get the same effect as above (version 2)
for (var i = 0; i < links.length; i++) {
(function(i){
links[i].onclick = function(event) {
alert(links[i].title);
}
})(i)
}
You need change .onclick for a eventlistener same:
function prepareShowElement () {
var nav = document.getElementById('nav');
var links = nav.getElementsByTagName('a');
for (var i = 0; i < links.length; i++) {
links[i].addEventListener('click',function() {
alert(links[i].title);
},false);
}
}