Using Javascript to apply CSS styles

I’m working on a page that was created by someone else, and which uses Javascript to apply CSS style changes to certain elements on the page. Basically we have a home-built CMS that lets you browse the web directory and edit files. You select a file be ticking a checkbox next to the filename, and the aforementioned Javascript “unhides” the buttons to edit, rename, or delete a file.

The Javascript is written in a way that if you select only one file, you have all options (edit, rename, and delete) but if you select more than one, you can only delete. It works very well, EXCEPT when there is only one item (file or subdirectory) in a directory, in which case you can’t unhide any buttons. Here’s the script in question.


    <script type="text/javascript">

    function hideButtons()
    {
                    document.getElementById('edit').style.visibility="hidden";
                    document.getElementById('rename').style.visibility="hidden";
                    document.getElementById('delete').style.visibility="hidden";
    }



    function showOptions()
    {
                    var thisItemChecked = 0;
                    if (document.getElementsByName('thisItem').length==1)
                    {
                                    if (document.getElementById('thisItem').checked==true)
                                    {
                                                    thisItemChecked++;
                                    }
                    } else if (document.getElementsByName('thisItem').length>1) {
                                    for (var i=0; i<document.editTopic.thisItem.length; i++)
                                    {
                                                    if (document.editTopic.thisItem[i].checked==true)
                                                    {
                                                                    thisItemChecked++;
                                                    }
                                    }
                    }
                    if (thisItemChecked==1)
                    {
                                    document.getElementById('edit').style.visibility="visible";
                                    document.getElementById('rename').style.visibility="visible";
                    } else {
                                    document.getElementById('edit').style.visibility="hidden";
                                    document.getElementById('rename').style.visibility="hidden";
                    }
                    if (thisItemChecked>=1)
                    {
                                    document.getElementById('delete').style.visibility="visible";
                    } else {
                                    document.getElementById('delete').style.visibility="hidden";
                    }
    }
    </script>

The HTML (all three buttons are like this):

<input type="image" name="edit" id="edit" src="images/edit_30x30.png" alt="Edit" title="Edit" />

And the checkbox that triggers the Javascript is like this:

<input type="checkbox" name="thisItem" id="thisItem#name#" value="#showDir##name#?type=#thisType#" onclick="showOptions();" />

(the funny #things# are ColdFusion variables, so you can ignore them)

The first function hides the buttons, and the other function does the rest. But why oh why won’t it work when there’s only one item in the directory?

What is the value of thisItemChecked when there is only one item in the directory?

Well I have to admit I’m not great with Javascript, so the only way I knew how to check this was to put an alert(thisItemChecked); in the JS code. If I put it up where it tests for zero, it returns zero. If I put it anywhere else, it doesn’t pop up.

If I leave it in the latter spot and browse to a directory with many items, it returns 1.

Let’s get more eyes on to this then. Link us to a page that allows us to experience the same problem.

This is in our CMS, so I’ll have to figure out a way to build a page that simulates the problem, because you have to be inside our building and on our network to get to the actual page in question. I think I can probably build a static version of the same page though, and stick it up on the web.

jsfiddle.net is a good place to put up a test page.

Here we go!

Hopefully it works!

Okay, thanks. Now the code can be examined in context to ther HTML code that it’s working with, an understanding of the problems can be arrived at.

It’s this part of the code that’s the cause of the matter, but there are several reasons and solutions to it.


var thisItemChecked = 0;
if (document.getElementsByName('thisItem').length==1) {
    if (document.getElementById('thisItem').checked==true) {
        thisItemChecked++;
    }
} else if (document.getElementsByName('thisItem').length>1) {
    for (var i=0; i<document.editTopic.thisItem.length; i++) {
        if (document.editTopic.thisItem[i].checked==true) {
            thisItemChecked++;
        }
    }
}

The first issue is that there are no elements with an id of “thisItem”


if ([document.[color="red"]getElementById('thisItem')[/color].checked==true) {

So we’ll remove that first if section, and just use the lower one if the number of items is more than or equal to 1. That equality change is something that you have already attempted on your test page too.


var thisItemChecked = 0;
[s][color="red"]if (document.getElementsByName('thisItem').length==1) {
    if (document.getElementById('thisItem').checked==true) {
        thisItemChecked++;
    }
} else [/color][/s]if (document.getElementsByName('thisItem').length [color="green"]>=[/color] 1) {

The next issue is that document.editTopic can have some troubles, so when accessing a form, it’s better to access it via the id attribute on the form.
This allows us to then to easily access the named elements of the form via the form.elements collection.


var thisItemChecked = 0[color="green"],
    form = document.getElementById('thisItem'),
    items = form.elements.thisItem[/color];
if ([s][color="red"]document.getElementsByName('thisItem')[/color][/s][color="green"]items[/color].length >= 1) {
    for (var i = 0; i < [s][color="red"]document.editTopic.thisItem[/color][/s][color="green"]items[/color].length; i += 1) {
        if ([s][color="red"]document.editTopic.thisItem[/color][/s][color="green"]items[/color][i].checked === true) {
            thisItemChecked += 1;
        }
    }
}

And finally, the loop won’t occur if there are 0 items, so the if condition around the loop can now be removed.


var thisItemChecked = 0,
    form = document.getElementById('thisItem'),
    items = form.elements.thisItem;
[s][color="red"]if (document.getElementsByName('thisItem')items.length >= 1) {[/color][/s]
    for (var i = 0; i < items.length; i += 1) {
        if (items[i].checked === true) {
            thisItemChecked += 1;
        }
    }
[s][color="red"]}[/color][/s]

Which leaves us with the following working code:


var thisItemChecked = 0,
    form = document.getElementById('thisItem'),
    items = form.elements.thisItem;
for (var i = 0; i < items.length; i += 1) {
    if (items[i].checked === true) {
        thisItemChecked += 1;
    }
}

At least by one of us! :smiley:

You’re right. It’s always “thisitem” with a variable appended to it, and that variable is the filename associated with the checkbox. In this case, that’s index.cfm.

But the first green line contains “getElementById(‘thisItem’)” and we just established that there isn’t an element with the ID “thisItem”. I’m confused.

I haven’t had success getting this to work, so I tried changing document.getElementById(‘thisItem’) to document.getElementByName(‘thisItem’) without any luck.

Oh weird! My reply is gone, but it looks like Paul’s answer is there as if it was posted by me. VERY strange!

Anyway, that did the trick! It needed to be the form’s ID. Works like a charm now! Thanks Paul.

My apologies on that. I chose edit instead of reply with quote, and at this late hour didn’t notice until too late. In reply to post #9:

That should be the id attribute of the form, which is editTopic instead.

I’ve set the jsfiddle to use nowrap and no library, and the following code is tested to work with the HTML code that you have there.

The array check with the items is due to a fun web browser inconsistancy, where if there’s only one item then that item is given, whereas with multiple items it’s an array-like collection that’s returned instead.


var thisItemChecked = 0,
    form = document.getElementById('editTopic'),
    items = form.elements.thisItem;
if (!items.length) {
    items = [items];
}
for (var i = 0; i < items.length; i += 1) {
    if (items[i].checked === true) {
        thisItemChecked += 1;
    }
}

Thanks again Paul, and again, it works perfectly (and I can almost make sense of it now!). It’s no wonder my usual “edit and hope” method of trying to get it to work wasn’t getting me anywhere.

I had actually considered putting a hidden form item on the page with the same name as a workaround to ensure there were always at least two items in the directory. :shifty: But it’s better go get it working the right way.