Using DOM Event Handlers with getElementsByClassName - javascript

I have a website I am working on that takes input from the user and calculates a results. All of the forms are html text input forms where they enter in certain number.
I want to use the input event to check for when the user enters a new value in one of these 6 text forms. The example in the book I am using, JavaScript and JQuery: Interactive Front-End Web Development, suggest to use the getElementById method with the dom event handler to do this:
For example:
function doWhatIwantToDo()
{
//Do something
}
var el = document.getElementById('username');
el.oninput = doWhatIwantToDo;
This is great and I could set up 6 unique ids for each text form, which I will need to do anyway in order to change their inner html in my javascript code, but is there someway I can check for input by using a class name?
I tried using getElementsByClassName but it is tripping me up because it returns an array of objects.
I want to avoid any jquery solutions right now because I am trying to learn vanilla javascript only right now.
Edit/Results:
I like "acbabis" and "mohamedrias" answers but the book implies that using Event Listeners is a newer method and not supported by all browsers. So for now, I would like to stick with the Traditional Dom Event Handlers that it talks about.
"dandavis" answer to just do it in a loop made me realize that perhaps binding an element to an event handler, in a loop, SHOULD actually work and that perhaps I was making a mistake in my loop.
I checked and stupidly I wasn't using array notation to loop through each object in the returned array which is why nothing was happening. Here is my final code that works:
var test = document.getElementsByClassName("test");
for (var i=0; i < test.length; i++)
{
console.log( test[i] );
test[i].onclick = testiness;
}
function testiness ()
{
alert("Success!");
}

var inputElements = document.querySelectorAll('.className');
for(var i = 0, len = inputElements.length ; i < len ; i++) {
inputElements[i].addEventListener('input', doSomethingFunction);
}
querySelectorAll returns you a static NodeList. You need to iterate and attach the event.
Instead of using getElementsByClassName which returns a live HTMLCollection, working with querySelectorAll would be preferrable.

I would document.querySelectorAll for this.
var inputs = document.querySelectorAll('input');
for(var i = 0; i < inputs.length; i++) {
inputs[i].addEventListener('input', doWhatIWantToDo);
}
This will find all input elements on the page and add the handler to each one. If you want to use a class, just add it to the desired input tags, and replace document.querySelectorAll('input') with document.querySelectorAll('input.classname').

Related

Traversing elements in javaScript

I need to change the href of link in a box. I can only use native javaScript. Somehow I have problems traversing through the elements in order to match the correct <a> tag.
Since all the a tags inside this container are identical except for their href value, I need to use this value to get a match.
So far I have tried with this:
var box = document.getElementsByClassName('ic-Login-confirmation__content');
var terms = box.querySelectorAll('a');
if (typeof(box) != 'undefined' && box != null) {
for (var i = 0; i < terms.length; i++) {
if (terms[i].href.toLowerCase() == 'http://www.myweb.net/2/') {
terms[i].setAttribute('href', 'http://newlink.com');
}
}
}
However, I keep getting "Uncaught TypeError: box.querySelectorAll is not a function". What do I need to do in order to make this work?
Jsfiddle here.
The beauty of querySelectorAll is you dont need to traverse like that - just use
var terms = document.querySelectorAll('.ic-Login-confirmation__content a');
And then iterate those. Updated fiddle: https://jsfiddle.net/4y6k8g4g/2/
In fact, this whole thing can be much simpler
var terms = document.querySelectorAll('.ic-Login-confirmation__content a[href="http://www.myweb.net/2/"]');
if(terms.length){
terms[0].setAttribute('href', 'http://newlink.com');
}
Live example: https://jsfiddle.net/4y6k8g4g/4/
Try This:
var box = document.getElementsByClassName('ic-Login-confirmation__content')[0];
Since you are using getElementsByClassName ,it will return an array of elements.
The getElementsByClassName method returns returns a collection of all elements in the document with the specified class name, as a NodeList object.
You need to specify it as follows for this instance:
document.getElementsByClassName('ic-Login-confirmation__content')[0]
This will ensure that you are accessing the correct node in your HTML. If you console.log the box variable in your example you will see an array returned.
you can select by href attr with querySelector,
try this:
document.querySelector('a[href="http://www.myweb.net/2/"]')
instead of defining the exact href attribute you can simplify it even more :
document.querySelector('a[href?="myweb.net/2/"]'
matches only elments with href attribute that end with "myweb.net/2/"

How to get multiple div id using queryselectorAll method

I want to add a functionality on click event.
I want to display none four div but this code seems doesn't work for me
Please tell me the mistake in this
<a class="lightbox-close" href="#" onclick="document.querySelectorAll('#goofy_1,#goofy_2,#goofy_3,#goofy_4').style.display = 'none';"></a>
The querySelectorAll returns a NodeList, you need to iterate over it and set the properties.
So it will be better to write a separate function where you can write the iteration logic
var els = document.querySelectorAll('#goofy_1,#goofy_2,#goofy_3,#goofy_4');
for (var i = 0; i < els.length; i++) {
els[i].style.display = 'none';
}
Query selector is not like jQuery selector where you can do
$('#goofy_1,#goofy_2,#goofy_3,#goofy_4')// it will get you all div selected
Instead Query selector returns nodeList which means you are getting
try console log your querySelectorAll
console.log( querySelectorAll('#goofy_1,#goofy_2,#goofy_3,#goofy_4'));
you will get something like
i.e i am selecting a
now you can see that there isnt single element selected so you can directly make any changes
Now you need to loop through all element like Arun P Johny telling
var allElements = document.querySelectorAll('#goofy_1,#goofy_2,#goofy_3,#goofy_4');
for (var i = 0; i < els.length; i++) {
allElements [i].style.display = 'none';
}
Good Read
Difference between HTMLCollection, NodeLists, and arrays of objects

How to get index value of a link with a specific class using plain JavaScript?

I have about 20 links with a specific class for links I want to target. If the 10th link is clicked, how can I get it's index value (I need "10" to be returned)?
I am using plain JavaScript so no jQuery!
Loop throught the elements, example
function linkOnClick(el) {
var elements = document.getElementsByClassName('className');
for (var i = 0; i < elements.length; i++) {
if (elements[i] == el) {
alert(i); // index of element
}
}
}
You are looking for a getElementsByClassName function. Latest versions of Firefox, Safari and Opera support this but if you want ultimate cross-browser compatibility, I would recommend this function found at: http://robertnyman.com/2008/05/27/the-ultimate-getelementsbyclassname-anno-2008/
Then you would loop through the returned elements in a function for the onclick attribute and test if the index matches the index required which you would pass through as a parameter
Edit: Exactly as written in the answer by IAbstractDownvoteFactor

How to iterate over HTML DOM nodes that contain one of the provided attributes?

I want to be able to get the first matching element, then the second, and so on, for the following CSS selector:
[att]
The below selectors are not valid CSS3 selectors, but that is what I'm trying to accomplish:
[att][0]
[att][1]
...
[att][n]
Can I combine multiple selectors and iterate over each matching node just like the example above?
[att1],[att2]
If this can't be done with native DOM or CSS3 selectors, then an XPath query is also an option.
If document.querySelectorAll() is an option, it will be very easy — just pass the selector and the browser will handle the rest:
var elms = document.querySelectorAll('[att]');
for (var i = 0; i < elms.length; ++i) {
alert(elms[i].tagName);
}
It works with any CSS selector you pass it provided the browser supports it (which in this case any browser implementing the function should already do). So to pick elements that have either att1, att2 or both, use this as mentioned in the comments:
var elms = document.querySelectorAll('[att1], [att2]');
Using jQuery:
$('[att]');
Also, this works:
$('[att1],[att2]');
The first will give you a list of all elements with an att attribute. If you don't want to use jQuery, your code will run much slower since the logical way to do this is:
var elems = document.getElementsByTagName('*');
for(var i=0, l=elems.length; i<l; i++){
if(elems[i].getAttribute('att')){
// do stuff
}
}
The reason jQuery is actually faster is because it will use XPath queries or other methods when possible, which will greatly speed up the execution. Of course you could implement XPath in the above code if you want.

getElementsByName in IE7

I have some code doing this :
var changes = document.getElementsByName(from);
for (var c=0; c<changes.length; c++) {
var ch = changes[c];
var current = new String(ch.innerHTML);
etc.
}
This works fine in FF and Chrome but not in IE7. Presumably because getElementsByName isn't working in IE. What's the best workaround?
In case you don't know why this isn't working in IE, here is the MSDN documentation on that function:
When you use the getElementsByName method, all elements in the document that have the specified NAME attribute or ID attribute value are returned.
Elements that support both the NAME attribute and the ID attribute are included in the collection returned by the getElementsByName method, but elements with a NAME expando are not included in the collection; therefore, this method cannot be used to retrieve custom tags by name.
Firefox allows getElementsByName() to retrieve elements that use a NAME expando, which is why it works. Whether or not that is a Good Thing™ may be up for debate, but that is the reality of it.
So, one option is to use the getAttribute() DOM method to ask for the NAME attribute and then test the value to see if it is what you want, and if so, add it to an array. This would require, however, that you iterate over all of the nodes in the page or at least within a subsection, which wouldn't be the most efficient. You could constrain that list beforehand by using something like getElementsByTagName() perhaps.
Another way to do this, if you are in control of the HTML of the page, is to give all of the elements of interest an Id that varies only by number, e.g.:
<div id="Change0">...</div>
<div id="Change1">...</div>
<div id="Change2">...</div>
<div id="Change3">...</div>
And then have JavaScript like this:
// assumes consecutive numbering, starting at 0
function getElementsByModifiedId(baseIdentifier) {
var allWantedElements = [];
var idMod = 0;
while(document.getElementById(baseIdentifier + idMod)) { // will stop when it can't find any more
allWantedElements.push(document.getElementById(baseIdentifier + idMod++));
}
return allWantedElements;
}
// call it like so:
var changes = getElementsByModifiedId("Change");
That is a hack, of course, but it would do the job you need and not be too inefficient compare to some other hacks.
If you are using a JavaScript framework/toolkit of some kind, you options are much better, but I don't have time to get into those specifics unless you indicate you are using one. Personally, I don't know how people live without one, they save so much time, effort and frustration that you can't afford not to use one.
There are a couple of problems:
IE is indeed confusing id="" with name=""
name="" isn't allowed on <span>
To fix, I suggest:
Change all the name="" to class=""
Change your code like this:
-
var changes = document.getElementById('text').getElementsByTagName('span');
for (var c=0; c<changes.length; c++) {
var ch = changes[c];
if (ch.className != from)
continue;
var current = new String(ch.innerHTML);
It's not very common to find elements using the NAME property. I would recommend switching to the ID property.
You can however find elements with a specific name using jQuery:
$("*[name='whatevernameYouWant']");
this will return all elements with the given name.
getElementsByName is supported in IE, but there are bugs. In particular it returns elements whose ‘id’ match the given value, as well as ‘name’. Can't tell if that's the problem you're having without a bit more context, code and actual error messages though.
In general, getElementsByName is probably best avoided, because the ‘name’ attribute in HTML has several overlapping purposes which can confuse. Using getElementById is much more reliable. When specifically working with form fields, you can more reliably use form.elements[name] to retrieve the fields you're looking for.
I've had success using a wrapper to return an array of the elements. Works in IE 6, and 7 too. Keep in mind it's not 100% the exact same thing as document.getElementsByName, since it's not a NodeList. But for what I need it for, which is to just run a for loop on an array of elements to do simple things like setting .disabled = true, it works well enough.
Even though this function still uses getElementsByName, it works if used this way. See for yourself.
function getElementsByNameWrapper(name) {
a = new Array();
for (var i = 0; i < document.getElementsByName(name).length; ++i) {
a.push(document.getElementsByName(name)[i]);
}
return a;
}
Workaround
var listOfElements = document.getElementsByName('aName'); // Replace aName with the name you're looking for
// IE hack, because it doesn't properly support getElementsByName
if (listOfElements.length == 0) { // If IE, which hasn't returned any elements
var listOfElements = [];
var spanList = document.getElementsByTagName('*'); // If all the elements are the same type of tag, enter it here (e.g.: SPAN)
for(var i = 0; i < spanList.length; i++) {
if(spanList[i].getAttribute('name') == 'aName') {
listOfElements.push(spanList[i]);
}
}
}
Just another DOM bug in IE:
Bug 1: Click here
Bug 2: Click here

Categories