Javascript get more than one id at a time - javascript

I'm just wondering if its possible in javascript to get more than one id at a time, without the use of JQuery. I'm checking the background color of each cell in a dynamically created table. For instance, I have this code:
var black = "rgb(0, 0, 0)";
if(document.getElementById("cell1").style.backgroundColor == black &&
document.getElementById("cell2").style.backgroundColor == black)
{
alert("Two cells are black!");
}
Would it be possible to do something like this:
var black = "rgb(0, 0, 0)";
if(document.getElementById("cell1","cell2").style.backgroundColor == black)
{
alert("Two cells are black!");
}
I'm trying not to use JQuery at all as I'm not too familiar with it.

With modern browsers you can do something similar using querySelectorAll (compatibility matrix), but you'd still have to loop over the resulting NodeList:
var nodes = document.querySelectorAll("#cell1, #cell2");
var count = 0;
for (var index = 0; index < nodes.length; ++index) {
if (nodes[index].style.backgroundColor == black) {
++count;
}
}
if (nodes.length === count) {
alert("Both are black");
}
Doesn't really buy you anything over, say:
var cells = ["cell1", "cell2"];
var count = 0;
for (var index = 0; index < cells.length; ++index) {
if (document.getElementById(cells[index]).style.backgroundColor == black) {
++count;
}
}
if (cells.length === count) {
alert("All cells are black");
}
So in short: No, there isn't really anything more useful you can do.

Not natively. You could write your own fairly easily, though:
function getElementsById(elements)
{
var to_return = [ ];
for(var i = 0; i < elements.length; i++)
{
to_return.push(document.getElementById(elements[i]));
}
return to_return;
}
This will accept an array of IDs as the parameter, and return the elements in an array. You might also want to look into the document.querySelector method.

No,
without using jQuery or other javascript helper libraries.
querySelector is not supported by IE7 and below which still represents a fairly large proportion of the traffice http://caniuse.com/#feat=queryselector

I have upvoted #BenM's answer, but I'd like to suggest another option.
Your issue:
I'm checking the background color of each cell
In this case, it would make more sense to attach the id to the table itself. Your selector becomes (assuming no nested table):
var cells = document.getElementById("myTable").getElementsByTagName("td");
or for recent browsers:
var cells = querySelectorAll("#myTable>tbody>tr>td");
For the record, here is another way if all your cells have a similar id "cellxxx":
var cells = querySelectorAll("td[id^='cell']");

Related

.hide() is not a function error when executing from a loop

I want to be able to loop over a few different labels and hide their content based on if a radio button is check or not. This is the solution I came up with, but I keep getting an error in the console.
var hazardOptions = $(".js-hazardous-option");
var hazard = $("input[name=Hazardous]");
for (var i = 0, len = hazard.length; i < len; i++) {
if (hazard[i].id === "HazardousYes" && hazard[i].checked) {
for (var ii = 0, length = hazardOptions.length; ii < length; ii++) {
hazardOptions[ii].show();
}
} else if (hazard[i].id === "HazardousNo" && hazard[i].checked) {
for (var iii = 0, leng = hazardOptions.length; iii < leng; iii++) {
hazardOptions[iii].hide();
}
}
}
The error I get is:
hide() is not a function
Not sure what I'm missing, I've tried having a look online for a similar issue, but with no luck. I'm pretty sure that the problem is here: hazardOptions[iii].hide(); but not really sure why and/or how to fix it.
When you have a list of objects from a JQuery selector, if you try to access them via index you actually get the DOM element back and not the JQuery object. It's confusing for sure but it is in the documentation.
What you effectively need to do is turn it back into a JQuery object:
$(hazardOptions[iii]).hide();
Or you can use the eq() function with does provide the JQuery object ad thus still has the hide() function:
hazardOptions.eq(iii).hide();
Most probably you need to wrap it with $
$(hazardOptions[ii]).hide()
As you currently have it, if hazard.id === "HazardousYes", you are showing all hazardOptions, and if it is "HazardousNo"you are hiding all of them.
You can call .show() and .hide() on a jQuery collection and it will apply that to all elements in the collection. The below code will replicate the logic of your original code, however, the hazardOptions final show/hide state will be solely determined by the last hazard that is checked and has an id equal to "HazardousYes" and "HazardousNo". This may be what you want, but I would imagine it's not.
var hazardOptions = $(".js-hazardous-option");
var hazards = $("input[name=Hazardous]");
hazards.each(function (index, hazard) {
if (hazard.checked) {
if (hazard.id === "HazardousYes") {
hazardOptions.show();
} else if (hazard.id === "HazardousNo") {
hazardOptions.hide();
}
}
}
Edit - Come to think of it, if you don't have elements with duplicate IDs, You can make this really simple:
hazardOptions.show($("#HazardousYes").is(":checked"));
hazardOptions.hide($("#HazardousNo").is(":checked"));

Changing classes with setInterval

I've made a 5x5 grid of tiles, and I'd like to create a tile that changes its class every 2 seconds.
Essentially, this tile would be turning, facing Up, Left, Down, Right -- in that particular order.
Right now, I'm putting all elements with a particular class into a nodeList/array.
Then, I iterate through each element, replacing the current color/class with the new one.
This kind of works, but appears to skip certain tiles, giving me wonky performance.
What am I doing wrong here?
function rotateTile(){
var tattleTowerUpArray = document.getElementsByClassName("tattleTowerUp");
var tattleTowerLeftArray = document.getElementsByClassName("tattleTowerLeft");
var tattleTowerDownArray = document.getElementsByClassName("tattleTowerDown");
var tattleTowerRightArray = document.getElementsByClassName("tattleTowerRight");
for(var i=0; i < tattleTowerUpArray.length; i++){
document.getElementById(tattleTowerUpArray.item(i).id).style.borderTopColor = "black";
document.getElementById(tattleTowerUpArray.item(i).id).style.borderLeftColor = "red";
document.getElementById(tattleTowerUpArray.item(i).id).classList.remove("tattleTowerUp");
document.getElementById(tattleTowerUpArray.item(i).id).classList.add("tattleTowerLeft");
}
for(var j=0; j < tattleTowerLeftArray.length; j++){
document.getElementById(tattleTowerLeftArray.item(j).id).style.borderLeftColor = "black";
document.getElementById(tattleTowerLeftArray.item(j).id).style.borderBottomColor = "red";
document.getElementById(tattleTowerLeftArray.item(j).id).classList.remove("tattleTowerLeft");
document.getElementById(tattleTowerLeftArray.item(j).id).classList.add("tattleTowerDown");
}
for(var k=0; k < tattleTowerDownArray.length; k++){
document.getElementById(tattleTowerDownArray.item(k).id).style.borderBottomColor = "black";
document.getElementById(tattleTowerDownArray.item(k).id).style.borderRightColor = "red";
document.getElementById(tattleTowerDownArray.item(k).id).classList.remove("tattleTowerDown");
document.getElementById(tattleTowerDownArray.item(k).id).classList.add("tattleTowerRight");
}
for(var l=0; l < tattleTowerRightArray.length; l++){
document.getElementById(tattleTowerRightArray.item(l).id).style.borderRightColor = "black";
document.getElementById(tattleTowerRightArray.item(l).id).style.borderTopColor = "red";
document.getElementById(tattleTowerRightArray.item(l).id).classList.remove("tattleTowerRight");
document.getElementById(tattleTowerRightArray.item(l).id).classList.add("tattleTowerUp");
}
}
Fixed your code and tried to comment it. You need to add class 'tattleTower' to EVERY tile element for this to work.
Just a couple of points:
1) getElementsByClassName returns a live NodeList. That means it looks for elements every time you access it(like when you access it's length property);
2) You can avoid using 4 loops and use just 1 loop with if statements, if you add a common class to ALL elements. Like in this example you could add a class 'tattleTower'. So each element would have 2 classes. eg: class='tattleTower tattleTowerLeft'.
3) I don't quite understand why you decided to change border styles with js. You could do it in CSS in those classes. You can explicitly define what properties you want transitions to work on if you're worried about it.
4) You don't need to use id to access a particular element within a loop. You can use el[i]. Eg. el[0] will give you the first element of the array.
5) Try to cache as much as possible by using variables if you perform expensive operations.
function rotateTile(){
// set up all variables at the top of the function
// use querySelectorAll for static NodeList, instead of live nodeList
var tattleTowerArray = document.querySelectorAll(".tattleTower"),
el, i, len, elClassList, elStyle;
// use one loop instead of four
// cache array's length for performance (to avoid asking for it on each iteration)
for (i = 0, len = tattleTowerArray.length; i < len; i++){
el = tattleTowerArray[i]; // cache element for performance
elClassList = el.classList; // cache element's classList
elStyle = el.style; // cache element's style object
// use 'if-else if' statements to check for class (you can change it to switch block, but i don't think it'd be best here)
if (elClassList.contains('tattleTowerUp')) {
elStyle.borderTopColor = "black";
elStyle.borderLeftColor = "red";
elClassList.remove("tattleTowerUp");
elClassList.add("tattleTowerLeft");
} else if (elClassList.contains('tattleTowerLeft')) {
elStyle.borderLeftColor = "black";
elStyle.borderBottomColor = "red";
elClassList.remove("tattleTowerLeft");
elClassList.add("tattleTowerDown");
} else if (elClassList.contains('tattleTowerDown')) {
elStyle.borderBottomColor = "black";
elStyle.borderRightColor = "red";
elClassList.remove("tattleTowerDown");
elClassList.add("tattleTowerRight");
} else if (elClassList.contains('tattleTowerRight')) {
elStyle.borderRightColor = "black";
elStyle.borderTopColor = "red";
elClassList.remove("tattleTowerRight");
elClassList.add("tattleTowerUp");
}
}
}

Delete object by attribute in javascript

I have a few different tables on the same page but unfortunately they were not assigned any unique id's. I want to remove a table using a JS command, but since id cannot be used, is it possible to delete a table based on a certain attribute it has? For example, is there a command to delete all tables on the page that have the attribute: width="25%" ?
You can use querySelectorAll to do that.
var x = document.querySelectorAll("table[width='25%']");
for (var i=0; i<x.length; i++) { //returns array of elements that match the attribute selector
x[i].remove(); //call prototype method defined below
}
Removing is tricky, I found this code that makes a nice remove method
Element.prototype.remove = function() {
this.parentElement.removeChild(this);
}
NodeList.prototype.remove = HTMLCollection.prototype.remove = function() {
for(var i = 0, len = this.length; i < len; i++) {
if(this[i] && this[i].parentElement) {
this[i].parentElement.removeChild(this[i]);
}
}
}
This creates a prototype remove() function that iterates the node and deletes the children.
Please note that querySelectorAll will not work in IE8 or below, but the poster of the prototype method said that it should work in IE8 but not 7.
I know this already has some solutions, but I'll offer up one more alternative.
var tables = document.getElementsByTagName('table');
for(var i = 0; i < tables.length; i++){
if(tables[i].getAttribute('width') == "25%"){
tables[i].parentNode.removeChild(tables[i]);
}
}
Demo at http://codepen.io/michaelehead/pen/HfdKx.
Yes you can. The easiest way is to use JQuery.
In your javascript code you would just write:
$("[attribute=value]").remove()
So in your case it could be something like $("table[width='25%']").remove()

Javascript getElemtsByClass select [all]

I want to select all elements with the css class
.arrow-down
Sorry but i simply dont find the correct answer, for my problem!
I have an javascript code:
document.getElementsByClassName("arrow-down")[0].style.borderTopColor=""+blu+"";
so how do i select not the first but [all] or is there a way to [1;2;3;]??
getElementsByClassName("arrow-down")[all]
getElementsByClassName("arrow-down")[1;2...]
I tried many things but simply dont get it!
Greetings from germany!
You need to iterate over the list of returned results.
var elements = document.getElementsByClassName("arrow-down");
for (var i = 0, len = elements.length; i < len; i++){
elements[i].style.borderTopColor = blu;
}
If you want to only do a specific subset based on the index, then you can add a condition that checks the value of i. I'm also assuming that blu here is a variable you have defined somewhere?
for (var i = 0, len = elements.length; i < len; i++){
if (i === 1 || i === 2 || i === 3){
elements[i].style.borderTopColor = blu;
}
}
Unfortunately, JavaScript does not have a shorthand for accessing a specific subset of array values, or for applying changes to multiple elements at once. That is something that jQuery does automatically for you. For instance, with jQuery you could write this as:
$('.arrow-down').css('borderTopColor', blu);
document.getElementsByClassName("arrow-down") does select all of such elements.
These are returned in a node list (which can be treated as an array), which is why using [0] on that returns the first element.
Loop over the different elements that the expression returns and act on them:
var elements = document.getElementsByClassName("arrow-down");
var elementsNum = elements.length)
for(var i = 0; i < elementsNum; i++)
{
var anElement = elements[i];
// do something with anElement
}

getElementByTagName not working?

In the code below, I am applying a different background color to all even rows by dynamically assigning the class "even" to them using javascript. I am calling the alternamte() function onload of the body tag.
At first, I was using getElementById to get the table object and my code worked fine. However, I am suppose to apply this styling to ALL tables on my page, so I need to use get element by tag name.
Once I made the chane to getElementByTagName, my code stopped working and I have been trying to find out the root of the problem for a while now with no success. I was wondering if someone can help me understand why my code stopped working after I made the change to getElementByTagName?
<script type="text/javascript">
function alternate(){
var table = document.getElementsByTagName("table");
var rows = table.getElementsByTagName("tr");
for(i = 0; i < rows.length; i++){
//change style of even rows
//(odd integer values, since we're counting from zero)
if(i % 2 == 0){
rows[i].className = "even";
}
}
}
</script>
It's getElementsByTagName(), plural. It returns a HTMLCollection
var table = document.getElementsByTagName("table")[0];
(if you're confident that there's a <table> on the page.)
If you want to do things to all the <table> elements, you'd have to do something like this:
var tables = document.getElementsByTagName("table");
for (var ti = 0; ti < tables.length; ++ti) {
var rows = tables[ti].getElementsByTagName("tr");
for(var i = 0; i < rows.length; i++){
//change style of even rows
//(odd integer values, since we're counting from zero)
if(i % 2 == 0){
rows[i].className = "even";
}
}
}
Use getElementsByTagName instead of getElementByTagName (getElementsByTagName return multiple node elements )
var table = document.getElementsByTagName("table")[0], trs, rl;
vat tl= table.length;
while(tl--){
trs = tables[tl].getElementsByTagName("tr");
rl = trs.length;
while(rl--){
if(rl % 2 == 0){
trs[rl].className = "even";
}
}
}
getElementsByTagName() returns an array matching the selector. Hence try
var table = getElementsByTagName('table')[indexnumber];

Categories