Edit:
The suggestion points to a jquery answer, which I would prefer not to use. I may have done a bad job explaining this. When you click on a class, I want to know which one it is of all the classes sharing that same name. For instance, if there are 8 buttons on the page with a classname of 'mybutton', when I click on one, I want to know which index it was ex: mybutton[3].
Original Post:
Is there a simple way to get the index of the class you clicked? I can't seem to find anything in the MouseEvent obj. I have searched stackoverflow/internet but what I can find seems to be over complicated,unanswered, or using jQuery. Example:
document.body.addEventListener('click',function(event){
console.log(event.target.className);
console.log(event.target.className.index??)`
});
I feel like it should be simple, no?
There's no "easy" way to do it; that is, the DOM API doesn't directly answer that sort of question. You can however simply search through the list of elements that match any characteristic you want and see which one your element matches:
function indexIn(selector, element) {
var list = document.querySelectorAll(selector);
for (var i = 0; i < selector.length; ++i)
if (list[i] === element) return i;
return -1;
}
Then your handler can look through the .classList on the clicked element:
document.body.addEventListener('click',function(event){
for (var i = 0; i < this.classList; ++i)
console.log("index for class " + this.classList[i] + ": " +
indexIn("." + this.classList[i], this));
});
Related
I have a variable that finds the data attribute of an element that is clicked on in a callback function:
var dropdown = document.getElementsByClassName('js-dropdown');
for (i = 0; i < dropdown.length; i++) {
dropdown[i].addEventListener("click", callBack (dropdown[i]));
}
function callBack (i) {
return function () {
var thisDropdown = i.getAttribute('data-dropdown');
//rest of the code here
}
}
I am basically trying to do this
$('#' + thisDropdown ).toggleClass('is-active');
...but in vanilla JS.
This works fine using jQuery however I would like a vanilla version.
So when a user clicks on an element that activates a drop down, I want it to dynamically find its relevant ID matching value within the document so it can toggle a show/hide class.
I've searched through a lot of SO questions and everyone replies with a jQuery answer which is not what I am looking for.
I've been trying to do something along the lines of
var idValue = document.getElementById(thisDropdown);
Then
var findId= idValue + thisDropdown;
findId.toggleClass('is-active');
Obviously that does not work the same way the jQuery statement works... any ideas?
Ignore the toggleClass method! Some of you may find this contradictory as I want vanilla JS.
To replace $('#' + thisDropdown ).toggleClass('is-active'); with plain js, use Element.classList. Like this:
const someElement = document.querySelector('#' + thisDropdown);
someElement.classList.toggle("is-active");
I like #kamyl's answer, but you might need backward compatibility. For that, see if you can find a polyfill.
If you have to write it yourself, use string.split(" ") to get your list of active attributes and iterate to find if it exists; add if not, remove if so...then array.join(" ") and replace the class attribute with it.
I have a javascript function with two parameters : results which is an object array and i which is the index.
The function displays item from that array. I also want to to build links to show other entries in the array.
My code is:
function renderNews(results, i) {
$('.articleTitle').text(results[i].Title);
$('.articleBody').text(results[i].newsBody);
// Build links
var linkHtml = '';
for (var i = 0; i < results.length; i++) {
linkHtml += '' + (i + 1) + ' ';
}
$('.articleActions').html(linkHtml);
}
As you can see I am setting my onclick for the function to call itself to redraw the results. I get a "function not defined error".
I'm still very much learning as I go. Is it bad idea for a function to call itself? I wonder if anyone can advise on the right way of doing this.
If I understand, renderNews will be called when the page gets loaded, right? Actually, your links would be put inside a component with articleActions class. By your idea, clicking any link would call this function again, and all links would be replaced by a new links. This sounds strange. Also, I can't tell what do you expect when passing that results to the onclick event. Actually, if your idea was to always reuse the same results array, passing it undefinitely to the same function over and over again, you could make things much simpler:
function renderNews(results) {
if (results.length == 0)
return;
// Build links
var linkHtml = '';
for (var i = 0; i < results.length; i++)
linkHtml += '' + (i + 1) + ' ';
$('.articleActions').html(linkHtml);
$('.articleTitle').text(results[0].Title);
$('.articleBody').text(results[0].newsBody);
}
$('.article-link').click(function(){
$('.articleTitle').text($(this).data('articletitle'));
$('.articleBody').text($(this).data('articlebody'));
});
As far as I understand, whenever you want to update the current articles, you call renderNews which will build/rebuild a lot of links for each article in the array holding their data (title and body), and will load the first item. So renderNews is going to be called once the page loads (I don't know how you intend to do this).
There is a click event for any component with article-link class, in this case all your links (anchors). When one is clicked, it updates the screen (article's title and body) with its data.
You could improve the code to keep track of the selected item, and once renderNews is called, you load that article instead of the first one. Or you could keep passing the article's index as parameter, like your example.
Since I don't know how do you call renderNews function, it's hard to make a better code, but this might clear something to you.
Simple JSFiddle demo
I'm learning JS but have hit a roadblock. I have links that have the attribute "number". I'd like to extract the value of "number" from each link, set it as a new variable, and then assign an onclick action to each link incorporating the corresponding value. I've been able to extract each value but don't know how to use them in the onclicks.
HTML
<a class="button call" href="#" number="6135555556">Call pager</a>
<a class="button call" href="#" number="6135555555">Call cell</a>
JS
var data = document.getElementsByClassName("call");
var numbers = '';
for (var i = 0; i < data.length; i++) {
numbers += data[i].getAttribute("number");
numbers[i].onclick = console.log("call " + numbers[i]);
}
If you want to the particular value on click of particular link then you can use this code.
var data = document.getElementsByClassName("call");
var numbers = [];
for (var i = 0; i < data.length; i++) {
data[i].onclick = getNumber;
}
function getNumber(){
numbers.push(this.dataset['number']);
alert(this.dataset['number']);
}
Here is the DEMO
There is no number property on anchor tag, so for your need we can use data-* property which allows you to store needful information on html.
This may not be entity correct, but assuming what you wanted was to console log the contained phone number whenever a link was clicked, there are probably 3 main changes you'd want to look at.
1) I'm guessing you wanted to connect your onclick event to the link element with the number in it data[i], rather to the number itself?
2) += will concatenate each found value on to the previous one. This may be what you wanted, although in the below code I've changed it only to log the current number
3) onclick expects to be passed a function, which it will then run when the click event is fired. Wrapping your console log in a function provides it to the onClick in the format it expects.
Assuming all that's right, the js to work with the above links should look something like this:
var data = document.getElementsByClassName("call");
for (var i = 0; i < data.length; i++) {
data[i].onclick = function() { console.log("call " + this.getAttribute("number")); }
}
Hope that helps :)
Edit: Updated the code to fix the bug james montagne pointed out below. The getAttribute is now performed within the context of the click event, meaning the issue with scoping is avoided. Sorry about that, completely missed the issue.
I have a checkbox contained within a form on my page. When the user clicks a button I need to find out which items in the checkbox have been selected.
I can get this to work with the following code without ay problems.
for (i=0; i < Form3.CBox1.length; i++)
if (Form3.CBox1[i].checked)
{
Answer = Answer + Form3.CBox1[i].value + ",";
}
alert(Answer);
The problem I have is that I call the above function several times on my page and I want to pass in variables instead of hard coding the name of the form and checkbox. Everytime I do this Javascript will not return anything. The variables vCurrForm & vCurrCBox, in the following code, have been set earlier in another function and I have tested to ensure that they are set correctly but I still can't get this piece of code to work.
for (i=0; i < vCurrForm.vCurrCBox.length; i++)
if (vCurrForm.vCurrCBox[i].checked)
{
Answer = Answer + vCurrForm.vCurrCBox[i].value + ",";
}
alert(Answer);
Any help would be greatly appreciated. Thanks
When working with variables as the keys to an object, you need to use the array syntax (ie. []s), which on its own would give us this (still broken) code:
for (i=0; i < vCurrForm[vCurrCBox].length; i++)
{
if (vCurrForm[vCurrCBox][i].checked)
{
Answer = Answer + vCurrForm[vCurrCBox][i].value + ",";
}
}
alert(Answer);
The problem is that vCurrForm is still being treated as a regular old variable, even though it's the string name of that variable. Because of this, you need to reference it from its parent; window:
for (i=0; i < window[vCurrForm][vCurrCBox].length; i++)
{
if (window[vCurrForm][vCurrCBox][i].checked)
{
Answer = Answer + window[vCurrForm][vCurrCBox][i].value + ",";
}
}
alert(Answer);
Without seeing how you are declaring and setting these values it is very difficult to ascertain the problem. It could be related to the type of object the variables are being set to, or their scope. Here are some things to check:
Ensure the variable vCurrForm.vCurrCBox is an array.
Ensure that vCurrForm and vCurrCBox are declared in a scope that is accessible to the function being called.
In this case make sure you are setting vCurrForm to a Form Object and vCurrCBox to an array of checkbox controls.
Looking at the code provided almost makes me think that the variable being referenced is for a single item (Current Checkbox). Your probably not going to get the results you are looking for in that case.
Something else to consider if it is possible would be to use JQuery to more easily grab the checked boxes and concatenate their values. In JQuery your code could be done with something like:
var Answers = "";
$("input[type='checkbox']:checked").each(function() { Answers += $(this).val() + ", "; });
Or, a better solution is to pass reference to the array that contains elements, instead of matching it with strings. For example:
function getAnswers(items) {
for (var i = 0; i < items.length; i++)
{
if (items[i].checked) {
Answer = Answer + items[i].value + ",";
}
}
}
Thank you ever so much for all you help. I've seen the error of my ways.
The following worked for me
**for (i=0; i < document[vCurrForm][vCurrCBox].length; i++)
if (document[vCurrForm][vCurrCBox][i].checked)
{
Answer = Answer + document[vCurrForm][vCurrCBox][i].value + ",";
}**
I am trying to create a function that given a divid, and a list of classes, will then do some text replacing inside them.
Having learned of how Firefox Dom is handling text nodes differently, I read that I had to use javascript to loop through the elements, sibling to nextSibling.
The last obstacle I had in my script, of which you see a small portion of, is getting the classname. I need the class name so that I can filter down what content get's text replaced.
Having looked all the answers, and with the help of a co-worker named Ryan at work, we have redone this in jquery.
$(divid).find(".status_bar").each( function() {
var value = $.trim($(this).text());
// if value is not defined thru browser bugs do not replace
if (typeof(value) != 'undefined') {
// it is a text node. do magic.
for (var x = en_count; x > 0; x--) {
// get current english phrase
var from = en_lang[x];
// get current other language phrase
var to = other_lang[x];
if (value == from) {
console.log('Current Value ['+value+'] English ['+from+'] Translation ['+to+']');
value = to;
$(this).attr('value', to);
}
}
}
});
This currently works in all areas, except in the replacing of text.
The reason I had originally with doing this in jQuery, had to be not sure I could loop thru elements, and avoid the problem with firefox and text nodes.
I am doing a loop of all elements inside a div, and I now need to get the classname of the element that I am looping by.
Then i can check if the current element's class is one, I need to do something with...
// var children = parent.childNodes, child;
var parentNode = divid;
// start loop thru child nodes
for(var node=parentNode.firstChild;node!=null;node=node.nextSibling){
var myclass = (node.className ? node.className.baseVal : node.getAttribute('class'));
}
But this code for getting the classname only get's null values.
Any suggestions?
For those of you who are trying to figure out what the whole point is, read this JavaScript NextSibling Firefox Bug Fix I have code that does my language translation that works in Google Chrome and IE. But when I use it in Firefox, and try to translate div content after ajax has loaded it, it fails because of the whitespace issue.
I really don't have a preference of jQuery or Pure Javascript, I just want a working solution.
Thank you all for being patient. I personally thought I was extremely clear in my description, I apologize if it wasn't. I wasn't trying to be obscure or make it difficult to get help. But please don't insult me, by implying I am trying to make it unclear.
Thanks.
Hm... You have jQuery but don't use it?
$(divid).children(".yourSpecialClassName").each( function() {
doSomethingWith(this);
});
To get the CSS class attribute value, this will do:
$(divid).children().each( function() {
alert(this.className);
});
Based on the function you posted now, you want this:
$(divid).find(".status_bar").each( function() {
$(this).text( function(i, text) {
var x = $.inArray(en_lang, $.trim(text));
if (x > -1) {
console.log('Current Value ['+text+'] English ['+en_lang[x]+'] Translation ['+other_lang[x]+']');
return other_lang[x];
}
return text;
});
});
And please, don't ever use "do magic" as a comment again. This is incredibly lame.
EDIT. This can be made much more efficient (superfluous console.log() removed):
$(divid).find(".status_bar").each( function() {
// prepare dictionary en_lang => other_lang
var dict = {};
$.each(en_lang, function(x, word) { dict[word] = other_lang[x]; });
$(this).text( function(i, text) {
var t = $.trim(text);
return (t in dict) ? dict[t] : text;
});
});
if you are using jquery you can do this:
$("#myDiv").find("*").each(
function(){
var myclass = $(this).attr("class");
}
);
Your sample code doesn't make sense.
$(this).attr('value', to);
'value' is an attribute of the tag, not the text content.
Did you really mean to do this instead?
$(this).text(to);
Also, you've re-edited your question, but you're still trying to loop through the child nodes using non-jQuery methods. You said "The last obstacle I had in my script, of which you see a small portion of, is getting the classname. I need the class name so that I can filter down what content get's text replaced."
If you are using jQuery it is completely unnecessary to loop through anything to get a class name. You simply have to use a proper selector in the first place.
$(divid).find(".status_bar.replaceme").each( function() {
// .replaceme is whatever class you're using for the stuff you want to change
// .status_bar.replaceme matches all elements with BOTH status_bar and replaceme classes
var value = $.trim($(this).text());
// if value is not defined thru browser bugs do not replace
if (typeof(value) != 'undefined') {
// it is a text node. do magic.
// NOTE: The following is inefficient but I won't fix it.
// You're better off using an associative array
for (var x = en_count; x > 0; x--) {
// get current english phrase
var from = en_lang[x];
// get current other language phrase
var to = other_lang[x];
if (value == from) {
console.log('Current Value ['+value+'] English ['+from+'] Translation ['+to+']');
// value = to; <-- useless, get rid of it.
$(this).text(to);
// or $(this).html(to);
}
}
}
});