Color Alternate Rows

I agree with that.

IF you already have jQuery included for the site then the one line of code is the simplest way to add the required functionality. In that case the only code you need to add is one line.

IF you do not already have jQuery used on the site then adding it in order to provide this simple functionality is stupid.

When comparing the readability of the code to perform a given function you can reasonably ignore the common functionality code used by the entire site but not the code that is included just to provide that function.\

So I will agree with you that the jQuery solution is more readable PROVIDED THAT the site is already making use of jQuery for lots of other things. It would be stupid to include the jQuery library if you only needed it for this functionality that can be done in just a handful of statements.

Hi, Frank S.

Almost…

I believe that the problem is that the following line targets grandchildren, too.


    else {
        var altie8_elem_children = altie8.getElementsByTagName('*');
    }

We should target only the immediate children of the parent container, which would be the row box (whether <tr>, <ul>, <div>, or whatever).

It’s easy enough in CSS:
The “>” symbol targets only immediate children.


.altrows > *:nth-child(odd) {background-color:#ffd;}

Can JS target only immediate children?

In light of the interesting differences of opinion, I intended to ask you and others to share your feelings/opinions about JS vs jQuery. I think the conclusion is essentially the same as mine… JS where reasonable, and jQuery when needed. I’ve started a few little projects with both and truly prefer the jQuery method of writing code. But just like in this exercise, sometimes a little JS is a better solution. It’s not easier, it just works better… and it doesn’t hurt that it weighs less :slight_smile:

Thanks for taking the initiative to open the chat :slight_smile:

Here’s one way: change altie8.getElementsByTagName('*'); to querySelectorAll('.altie8 &gt; *');

Interesting, but can you make a demo of it? I can’t get it to work.

Duh. Sorry, it should have been [COLOR="#FF0000"]document[/COLOR].querySelectorAll('.altie8 &gt; *')

I still can’t get it working – the table rows all get colored pink. JSBin demo?

I wonder how many times I can mess this up! I wasn’t really looking at it in the contenxt of the script, I’m afraid. As I had it, the else clause selects all children, including the tbody element, which is no good. I should have done this, I think: altie8.querySelectorAll('.altie8 > *'). As you can see, I’m a JS noob and should stay out of conversations like this. :rolleyes:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Demo alternating coloring</title>
<style>
.altie8_oddChild {
    background-color: pink;
}
table {
    width: 100%;
    border-collapse: collapse;
}
td {
    height: 15px;
    border: 1px solid black;
}
</style>
</head>
<body>
    <div class="altie8">
        <p>I am an odd paragraph</p>
        <p>I am an even paragraph</p>
        <p>I am an odd paragraph</p>
        <p>I am an even paragraph</p>
        <p>I am an odd paragraph</p>
        <p>I am an even paragraph</p>
    </div>

    <table class="altie8">
        <tbody>
            <tr>
                <td>I am the first cell in an odd table row</td>
                <td>I am the second cell in an odd table row</td>
            </tr>
            <tr>
                <td>I am the first cell in an even table row</td>
                <td>I am the second cell in an even table row</td>
            </tr>
            <tr>
                <td>I am the first cell in an odd table row</td>
                <td>I am the second cell in an odd table row</td>
            </tr>
            <tr>
                <td>I am the first cell in an even table row</td>
                <td>I am the second cell in an even table row</td>
            </tr>
            <tr>
                <td>I am the first cell in an odd table row</td>
                <td>I am the second cell in an odd table row</td>
            </tr>
            <tr>
                <td>I am the first cell in an even table row</td>
                <td>I am the second cell in an even table row</td>
            </tr>
        </tbody>
    </table>
<script>
var altie8s = document.querySelectorAll('.altie8'); // no IE8 support for getElementsByClassName; mind the dot
for (var i=0; i<altie8s.length; i++) {
    var altie8 = altie8s[i];

    if (altie8.tagName == 'TABLE') { // must be uppercase
    	var altie8_elem_children = altie8.querySelectorAll('tr');
    }
    else {
        var altie8_elem_children = altie8.querySelectorAll('.altie8 > *');
    }

    for (var k=0; k<altie8_elem_children.length; k+=2) {
        altie8_elem_children[k].className += ' altie8_oddChild';
    }
}
console.log(altie8_elem_children.length);
</script>
</body>
</html>

It seems to me that if one requires the class .altie8 to be added to the parent container, which for HTML tables means the <tbody> tag, then the simple immediate child selector and the wild card seem to work in the 4 situations that I have tried: table tbody.altie8 > tr, ul.altie8 > li, div.altie8 > p, div.altie8 > div div .

Since we are talking about someone who still wants to code for IE8, I would not feel bad about stipulating that the altie8 class must be applied to the <tbody> tag for tables.

Your thoughts?

But that isn’t required, as the example above shows.

YES!!!

That’s perfect! I had plugged your line of JS in incorrectly so it wasn’t working. I should have copied your working page, instead.

It looks like changing “var k=0” to “var k=1” changes the rows from odd to even. :slight_smile:

And finally, I assume that it’s OK to put IE8 CCs around the entire script to keep it from running unnecessarily ?

May I ask where to find the console log? I looked last night but couldn’t figure it out. :-/

Thanks everyone !!!

This REALLY makes me want to dive into a good, recent JS book. :smiley:

Cheers

In most browsers F12 will bring up the developer tools and the console is one of the tabs there.

That in itself works, but that complicates rather than simplifies the code I gave earlier. And it doesn’t start counting anew with the next parent element. However, there is an interesting thing about your script line – its ability to select only the direct children. This code (JSBin live demo) shows both:


<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Demo alternating coloring</title>
<style>
.altie8_oddChild {
    background-color: pink;
}
button {
    width: 100px;
}
</style>
</head>
<body>
    <div class="altie8">
        <p>I am an odd paragraph <span>with a span</span></p>
        <p>I am an even paragraph</p>
        <p>I am an odd paragraph</p>
        <p>I am an even paragraph</p>
        <p>I am an odd paragraph</p>
        <p>I am an even paragraph</p>
        <p>I am an odd paragraph</p>
    </div>

    <ul class="altie8">
        <li>I am an odd list item</li>
        <li>I am an even list item</li>
        <li>I am an odd list item</li>
        <li>I am an even list item</li>
        <li>I am an odd list item</li>
        <li>I am an even list item</li>
    </ul>

    <button type="button" onclick="coloringScript_1()">Script 1</button>
        <br>
    <button type="button" onclick="location.reload()">Reload</button>
        <br>
    <button type="button" onclick="coloringScript_2()">Script 2</button>

<script>
function coloringScript_1() {
    var altie8_elem_children = document.querySelectorAll('.altie8 > *');
    for (var i=0; i<altie8_elem_children.length; i+=2) {
        altie8_elem_children[i].className += ' altie8_oddChild';
    }
}

function coloringScript_2() {
    var altie8s = document.querySelectorAll('.altie8');
    for (var i=0; i<altie8s.length; i++) {
        var altie8 = altie8s[i];
        var altie8_elem_children = altie8.getElementsByTagName('*');
        for (var k=0; k<altie8_elem_children.length; k+=2) {
            altie8_elem_children[k].className += ' altie8_oddChild';
        }
    }
}
</script>
</body>
</html>

So, it was a good thing to get involved in the discussion after all.

The console is part of Firebug and the likes. Open Firebug, click ‘Console’ and then ‘All’, and reload the page.

A good, recent JS book is much more difficult. Among other things because books generally don’t come with live demos (some do, on CD, but those are rare). And the interweb and a good forum is all you need anyway.

I should have included the working script, too. Here is the updated JSBin, in which two dysfunctional and the functional generic scripts are included. Which at the same time shows that Ralph was right after all, in post #28. I, too, should have looked at and have tested the whole code. Way to go, Ralph! :slight_smile:

Thanks, felgall. As I said, I was there last night but couldn’t figure out how it worked. After your nudge tonight, I went back and gave it a more thorough look and finally figured out how it opens. Sometimes it takes reinforcement to know that I’m on the right track.

Thanks again :slight_smile:

Hi Ron,

This is a good read and may help you in the future: http://juliepagano.com/blog/2014/05/18/javascript-debugging-for-beginners/

This is pretty much the test page that evolved while I was working on this code (applied to Frank’s demo). Interestingly, .altie8 can be applied to the <table> tag or the <thead> tag.


<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
<!-- Changes:
oddChild to altChild

-->
    <title>Demo alternating coloring</title>
    <style>
*, *:before, *:after {
    -webkit-box-sizing:border-box;
    -moz-box-sizing:border-box;
    box-sizing:border-box;
}

.altie8_altChild {
    background-color:#fdd;
}

.aboxofpees {
    border: 1px solid red;
}
p {
    padding:.375em .5em;
    margin:0;
}

table {
    width:100%;
    border-collapse:collapse;
    margin-bottom:1em;
}
td {
    border:1px solid black;
}

ol {
    list-style-position:inside;
    border: 1px solid blue;
    padding:0;
}
li {padding:.25em .5em;}

.outer {
    font-size:14px;
    line-height:14px;
    font-family:'lucida console', monospace;
    margin:0;
}
.outer > div {
    border:1px solid #ccc;
    border-top:0;
    overflow:hidden;
}
.outer > div:first-child {border-top:1px solid #ccc;}
[class^="column"] {
    width:14%;
    float:left;
    border-left:1px dotted #ccc;
    color:#000;
    text-align:left;
    padding:.5em 1%;
}
.column1 {
    text-align:right;
    width:6%;
    border-left:0
}
.column2 {width:35%;}
.column7 {width:3%;}

button {
    width:100px;
    clear:left;
    float:left;
}
button:first-of-type {margin-top:1em;}
    </style>
</head>
<body>

<div class="aboxofpees altie8">
    <p>I am an odd and unusually entertaining paragraph. <span>I will delight you for hours.</span></p>
    <p>I am an even but mostly boring paragraph. <span>I am a fine example of dry reading.</span></p>
    <p>I am an odd and unusually entertaining paragraph. I will delight you for hours.</p>
    <p>I am an even but mostly boring paragraph. I am a fine example of dry reading.</p>
    <p>I am an odd and unusually entertaining paragraph. I will delight you for hours.</p>
</div>

<ol class="altie8">
    <li>I am an odd list item</li>
    <li>I am an even list item</li>
    <li>I am an odd list item</li>
    <li>I am an even list item</li>
    <li>I am an odd list item</li>
</ol>

<table class="altie8">
    <tbody>
        <tr>
            <td>I am the first cell in an odd table row</td>
            <td>I am the second cell in an odd table row</td>
        </tr>
        <tr>
            <td>I am the first cell in an even table row</td>
            <td>I am the second cell in an even table row</td>
        </tr>
        <tr>
            <td>I am the first cell in an odd table row</td>
            <td>I am the second cell in an odd table row</td>
        </tr>
        <tr>
            <td>I am the first cell in an even table row</td>
            <td>I am the second cell in an even table row</td>
        </tr>
        <tr>
            <td>I am the first cell in an odd table row</td>
            <td>I am the second cell in an odd table row</td>
        </tr>
    </tbody>
</table>

<table>
    <tbody class="altie8">
        <tr>
            <td>I am the first cell in an odd table row</td>
            <td>I am the second cell in an odd table row</td>
            <td>I am the third cell in an odd table row</td>
        </tr>
        <tr>
            <td>I am the first cell in an even table row</td>
            <td>I am the second cell in an even table row</td>
            <td>I am the third cell in an even table row</td>
        </tr>
        <tr>
            <td>I am the first cell in an odd table row</td>
            <td>I am the second cell in an odd table row</td>
            <td>I am the third cell in an odd table row</td>
        </tr>
        <tr>
            <td>I am the first cell in an even table row</td>
            <td>I am the second cell in an even table row</td>
            <td>I am the third cell in an even table row</td>
        </tr>
        <tr>
            <td>I am the first cell in an odd table row</td>
            <td>I am the second cell in an odd table row</td>
            <td>I am the third cell in an odd table row</td>
        </tr>
    </tbody>
</table>

<p>We are rows of divs.</p>
<div class="outer altie8">
    <div>
        <div class="column1">col1</div>
        <div class="column2">col2</div>
        <div class="column3">col3</div>
        <div class="column4">col4</div>
        <div class="column5">col5</div>
        <div class="column6">col6</div>
        <div class="column7">7</div>
    </div>
    <div>
        <div class="column1">col1</div>
        <div class="column2">col2</div>
        <div class="column3">col3</div>
        <div class="column4">col4</div>
        <div class="column5">col5</div>
        <div class="column6">col6</div>
        <div class="column7">7</div>
    </div>
    <div>
        <div class="column1">col1</div>
        <div class="column2">col2</div>
        <div class="column3">col3</div>
        <div class="column4">col4</div>
        <div class="column5">col5</div>
        <div class="column6">col6</div>
        <div class="column7">7</div>
    </div>
    <div>
        <div class="column1">col1</div>
        <div class="column2">col2</div>
        <div class="column3">col3</div>
        <div class="column4">col4</div>
        <div class="column5">col5</div>
        <div class="column6">col6</div>
        <div class="column7">7</div>
    </div>
</div>

<button type="button" onclick="coloringScript_1()">Script 1</button>
<button type="button" onclick="location.reload()">Reload</button>
<button type="button" onclick="coloringScript_2()">Script 2</button>
<button type="button" onclick="location.reload()">Reload</button>
<button type="button" onclick="coloringScript_3()">Script 3</button>

    <script>
function coloringScript_1() {
    var altie8_elem_children = document.querySelectorAll('.altie8 > *');
    for (var i=0; i<altie8_elem_children.length; i+=2) {
        altie8_elem_children[i].className += ' altie8_altChild';
    }
}

function coloringScript_2() {
    var altie8s = document.querySelectorAll('.altie8');
    for (var i=0; i<altie8s.length; i++) {
        var altie8 = altie8s[i];
        var altie8_elem_children = altie8.getElementsByTagName('*');
        for (var k=0; k<altie8_elem_children.length; k+=2) {
            altie8_elem_children[k].className += ' altie8_altChild';
        }
    }
}

function coloringScript_3() {
    var altie8s = document.querySelectorAll('.altie8');
    for (var i=0; i<altie8s.length; i++) {
        var altie8 = altie8s[i];
        if (altie8.tagName == 'TABLE') { // must be uppercase
            var altie8_elem_children = altie8.getElementsByTagName('tr');
        }
        else {
            var altie8_elem_children = altie8.querySelectorAll('.altie8 > *');
        }
        for (var k=0; k<altie8_elem_children.length; k+=2) {
            altie8_elem_children[k].className += ' altie8_altChild';
        }
    }
}
	</script>
</body>
</html>


There is one line of difference between Ralph’s JS and Frank’s in the third script:
Ralph


        if (altie8.tagName == 'TABLE') { // must be uppercase
            var altie8_elem_children = altie8.[color=blue]querySelectorAll[/color]('tr');
        }
        else {
            var altie8_elem_children = altie8.querySelectorAll('.altie8 > *');
        }

Frank


        if (altie8.tagName == 'TABLE') { // must be uppercase
            var altie8_elem_children = altie8.[color=blue]getElementsByTagName[/color]('tr');
        }
        else {
            var altie8_elem_children = altie8.querySelectorAll('.altie8 > *');
        }

I can’t see a difference in the operation of the script. They both work splendidly. Frank, since your code was last, would you care to elaborate about the diff?

I will rename .altie8 to something else, like maybe altchild. It has a good ring to it and is potentially more descriptive. CSS for modern browsers can be written to use that tag, too. IE8 won’t see it and the JS can be hidden in IE8 CCs until needed.

Simple project, but really cool outcome.

Thanks again, everyone!

Ron

For static pages, there isn’t any. Then it’s just a matter of preference. For Ajax-altered pages, there might be a difference, because getElementsBy~ returns a dynamic nodeList, while querySelectorAll returns a static one.

That might by all Greek to you, but I can explain and offer a work-around. But first I would like to ask Felgall whether it is true or not that with a script with querySelectorAll, Ajax-updated pages are not repainted automatically, or not correctly? And that with getElementsBy~ they are?

Whichever of getElementsBy~ and querySelectorAll that you use would not affect any updates you make to the HTML. It would only affect whether or not those updates are applied to the nodeList that you returned from the call.

If the HTML is updated after a querySelectorAll call is made then the nodelist no longer matches what is in the HTML.

Thank you, @James_Hibbard ; It is now a JS folder bookmark :slight_smile: She sounds like she can relate to the material (and the people). :stuck_out_tongue: