getElementsByClassName is not a function in Firefox

38,731

Solution 1

There are at least 3 problems in that code:

  1. You cannot chain getElementsByClassName like that. That function operates on a DOM element, but returns an object.

  2. for (var book in books) will loop on object properties that are not accounted for, and will crash this code. books is an object, not an array.

  3. book.style.backgroundColor is not a function and that is not how to set a style.

  4. Nowadays, getElementsByClassName is seldom the best approach for this kind of thing; use querySelectorAll for more: flexibility/power/precision.

Fixing all the problems, here's code that should work -- assuming that the page structure really matches the code structure from the question. Post a relevant HTML snippet and/or link to the exact page, if it does not.

// ==UserScript==
// @name        Unpublished Lowlighter
// @description Makes the background of books not yet published on the Goodreads to-read shelf grey.
// @include     http://www.goodreads.com/*
// ==/UserScript==

function dateColor() {
    var books = document.querySelectorAll (
        ".bookalike.review .field.date_pub .value"
    );
    var today = new Date(); // More efficient, outside the loop.

    for (var J = books.length - 1;  J >= 0;  --J) {
        var book        = books[J];
        var dateString  = book.textContent;
        var date        = new Date(dateString);
        if (date > today) {
            book.parentNode.parentNode.style.setProperty ("background", "Lightgrey");
        }
    }
}

dateColor();

Solution 2

There is a further problem (aside from trying to call getElementsByClassName on a NodeList) that for (var book in books) won't do what you want. in doesn't do a foreach as you would expect; it gets every property from the target object. Because of the way Javascript objects work, for an array, this would be the array indexes; for a NodeList, it is the properties of the NodeList (which will be the array indexes, plus the string "length" and the string "item"), which will not be useful for your loop.

You need something like

for (var i = 0; i < books.length; ++i) {
    var book = books[i];
    ...
}

Solution 3

This won't work:

book
    .getElementsByClassName('field date_pub')
    .getElementsByClassName('value')

getElementsByClassName returns an array-like object of the appropriate elements (there can be more than one with a given class). You will have to loop over each one and execute getElementsByClassName on each. Nested getElementsByClassNames are not merged by default.

Solution 4

You can only use getElementsByClassName on a single Element object, not a NodeList or HTMLCollection like what's returned by getElementsByClassName. That is, the problem probably lies in your chaining call where you call that function again on itself.

Solution 5

The problem is that you're calling the function from the array returned by getElementsByClassName.

Assuming that you're just looking for the first element with the class name, this should work:

var dateString = book
                    .getElementsByClassName('field date_pub')[0]
                    .getElementsByClassName('value')[0]
                    .textContent;
Share:
38,731
Mr Alpha
Author by

Mr Alpha

Updated on September 23, 2020

Comments

  • Mr Alpha
    Mr Alpha over 3 years

    My to-read shelf on GoodReads is a mix of published and unpublished books making it hard to find something published to read. I figured I could throw together a GreaseMonkey script that would change the background of the entry for the books that haven't yet been published.

    This is what I have put together so far:

    // ==UserScript==
    // @name        Unpublished Lowlighter
    // @description Makes the background of books not yet published on the Goodreads to-read shelf grey.
    // @include     http://www.goodreads.com/*
    // ==/UserScript==
    
    function dateColor() {
        var books = document.getElementsByClassName('bookalike review');
        for (var book in books) {
            var dateString = book
                            .getElementsByClassName('field date_pub')
                            .getElementsByClassName('value')
                            .textContent;
            var date = new Date(dateString);
            var today = new Date();
            if (date > today) {
                book.style.backgroundColor('Lightgrey');
            }
        }
    }
    
    dateColor();
    

    The problem is that it doesn't work. When I tried running the script in scratchpad it gives me the error: Exception: book.getElementsByClassName is not a function

    I was under the impression that Firefox supports getElementsByClassName and that you can run it on the result of getElementsByClassName to get the child elements. Where am I going wrong?

    EDIT: Here is a snippet of the HTML for one <tr> in the table. The reason that I didn't post this to begin with is that it is really verbose:

    <tr id="review_265364012" class="bookalike review">
      <td class="field checkbox" style="display: none"><label>checkbox</label><div class="value">      <input id="checkbox_review_265364012" name="reviews[265364012]" value="265364012" type="checkbox">
    </div></td>  <td class="field position"><label>position</label><div class="value">        <div class="reorderControls">
                <a class="actionLink" href="#" id="loading_link_434018960" method="post" onclick="$(this).hide(); $('loading_anim_434018960').show(); $('hidden_link_434018960').simulate('click');; return false;"><img alt="up" src="http://www.goodreads.com/assets/up_arrow-7957f2bae9c3456ec7359ad79b000652.gif" title="move book up"></a><img alt="Loading-trans" class="loading" id="loading_anim_434018960" src="http://www.goodreads.com/assets/loading-trans-3e04cd6ed6ad31063972e688820d7866.gif" style="display:none"><a href="/shelf/move_up/174788201?redirect_url=%2Freview%2Flist%2F4111865%3Fformat%3Dhtml%26page%3D1%26shelf%3Dto-read" class="actionLink" data-method="post" id="hidden_link_434018960" rel="nofollow" style="display: none"><img alt="up" src="http://www.goodreads.com/assets/up_arrow-7957f2bae9c3456ec7359ad79b000652.gif" title="move book up"></a>
              <img src="/assets/loading.gif" class="position_loading" style="display: none">
              <input id="positions_174788201" name="positions[174788201]" value="5" type="text">
              <script type="text/javascript">
    //<![CDATA[
          var newTip = new Tip($('positions_174788201'), "            <nobr>\n              <a class=\"button\" href=\"#\" onclick=\"savePositionChanges(4111865); return false;\">Save position changes<\/a> &nbsp;\n              <a href=\"#\" onclick=\"$(\'positions_174788201\').prototip.hide(); return false;\">close<\/a>\n            <\/nobr>\n", { style: 'creamy', stem: 'leftMiddle', hook: { tip: 'leftMiddle', target: 'rightMiddle' }, offset: { x: 5, y: 5 }, hideOn: 'imaginaryelement', showOn: 'click', width: 'auto', hideOthers: true });
          $('positions_174788201').observe('prototip:shown', function() {
            if (this.up('#box')) {
              $$('div.prototip')[0].setStyle({zIndex: $('box').getStyle('z-index')});
            } else {
              $$('div.prototip')[0].setStyle({zIndex: 6000});
            }
          });
    
    //]]>
    </script>            <a class="actionLink" href="#" id="loading_link_434206980" method="post" onclick="$(this).hide(); $('loading_anim_434206980').show(); $('hidden_link_434206980').simulate('click');; return false;"><img alt="down" src="http://www.goodreads.com/assets/down_arrow-61b0e7292c02b1dcfd3f75a7f9b6b7ad.gif" title="move book down"></a><img alt="Loading-trans" class="loading" id="loading_anim_434206980" src="http://www.goodreads.com/assets/loading-trans-3e04cd6ed6ad31063972e688820d7866.gif" style="display:none"><a href="/shelf/move_down/174788201?redirect_url=%2Freview%2Flist%2F4111865%3Fformat%3Dhtml%26page%3D1%26shelf%3Dto-read" class="actionLink" data-method="post" id="hidden_link_434206980" rel="nofollow" style="display: none"><img alt="down" src="http://www.goodreads.com/assets/down_arrow-61b0e7292c02b1dcfd3f75a7f9b6b7ad.gif" title="move book down"></a>
            </div>
    </div></td>  <td class="field cover"><label>cover</label><div class="value">      <a href="/book/show/12074927-the-fractal-prince"><img alt="The Fractal Prince (The Quantum Thief Trilogy #2)" src="http://photo.goodreads.com/books/1311105989s/12074927.jpg" title="The Fractal Prince (The Quantum Thief Trilogy #2)"></a>
    </div></td>  <td class="field title"><label>title</label><div class="value">    <a href="/book/show/12074927-the-fractal-prince" title="The Fractal Prince (The Quantum Thief Trilogy #2)">
          The Fractal Prince
            <span class="darkGreyText">(The Quantum Thief Trilogy #2)</span>
    </a></div></td>  <td class="field author"><label>author</label><div class="value">      <a href="/author/show/2768002.Hannu_Rajaniemi">Rajaniemi, Hannu</a>
    </div></td>  <td class="field isbn" style="display: none"><label>isbn</label><div class="value">    
    </div></td>  <td class="field isbn13" style="display: none"><label>isbn13</label><div class="value">    
    </div></td>  <td class="field asin" style="display: none"><label>asin</label><div class="value">    
    </div></td>  <td class="field num_pages" style="display: none"><label>num pages</label><div class="value">      <span class="greyText">unknown</span>
    </div></td>  <td class="field avg_rating"><label>avg rating</label><div class="value">    3.67
    </div></td>  <td class="field num_ratings" style="display: none"><label>num ratings</label><div class="value">    9
    </div></td>  <td class="field date_pub"><label>date pub</label><div style="background: none repeat scroll 0% 0% Lightgrey;" class="value">      Sep 27, 2012
    </div></td>  <td class="field date_pub_edition" style="display: none"><label>date pub edition</label><div class="value">      <span class="greyText">unknown</span>
    </div></td>    <td class="field rating"><label>my rating</label><div class="value">
        <span class="stars" id="stars12074927_4111865" onmouseout="mouseOutStars('12074927')"><a rel="nofollow"><img alt="didn't like it " class="star" id="star12074927_0" onclick="submitStars('12074927', 0, '/review/rate/12074927?rating=1', 4111865);  return false;" onmouseover="checkStars('12074927', 0)" src="/assets/layout/gr_orange_star_inactive.png" title="didn't like it" height="15" width="15"></a><a rel="nofollow"><img alt="it was ok " class="star" id="star12074927_1" onclick="submitStars('12074927', 1, '/review/rate/12074927?rating=2', 4111865);  return false;" onmouseover="checkStars('12074927', 1)" src="/assets/layout/gr_orange_star_inactive.png" title="it was ok" height="15" width="15"></a><a rel="nofollow"><img alt="liked it " class="star" id="star12074927_2" onclick="submitStars('12074927', 2, '/review/rate/12074927?rating=3', 4111865);  return false;" onmouseover="checkStars('12074927', 2)" src="/assets/layout/gr_orange_star_inactive.png" title="liked it" height="15" width="15"></a><a rel="nofollow"><img alt="really liked it " class="star" id="star12074927_3" onclick="submitStars('12074927', 3, '/review/rate/12074927?rating=4', 4111865);  return false;" onmouseover="checkStars('12074927', 3)" src="/assets/layout/gr_orange_star_inactive.png" title="really liked it" height="15" width="15"></a><a rel="nofollow"><img alt="it was amazing " class="star" id="star12074927_4" onclick="submitStars('12074927', 4, '/review/rate/12074927?rating=5', 4111865);  return false;" onmouseover="checkStars('12074927', 4)" src="/assets/layout/gr_orange_star_inactive.png" title="it was amazing" height="15" width="15"></a></span><script language="javascript" type="text/javascript">starRatings[ratingIndex++] = [ '12074927', -1]; checkStars('12074927', -1);</script>
        <span id="reviewMessage12074927_4111865"></span>
        <span id="successMessage12074927_4111865"></span>
    </div></td><td class="field shelves"><label>shelves</label><div class="value">    <span id="shelfList4111865_12074927"><span id="shelf_174788201"><a href="http://www.goodreads.com/review/list/4111865?shelf=to-read" class="shelfLink" title="View all books in Johan's to-read shelf.">to-read</a></span></span><br><a class="shelfChooserLink smallText" href="#" onclick="window.shelfChooser.summon(event, {bookId: 12074927, chosen: [&quot;to-read&quot;]}); return false;">[edit]</a>
    </div></td><td class="field review" style="display: none"><label>review</label><div class="value">    <span class="greyText">None</span>
        <a class="floatingBoxLink smallText" href="#" onclick="reviewEditor.summon(this, 12074927, 'review', {value: null}); return false;">[edit]</a>
      <div class="clear"></div>
    </div></td><td class="field notes" style="display: none"><label>notes</label><div class="value">      <span class="greyText">None</span>
          <a class="floatingBoxLink smallText" href="#" onclick="reviewEditor.summon(this, 12074927, 'notes', {value: null}); return false;">[edit]</a>
    </div></td><td class="field recommender" style="display: none"><label>recommender</label><div class="value">    <span class="greyText">none</span>
    </div></td><td class="field comments" style="display: none"><label>comments</label><div class="value">  <a href="/review/show/265364012">0</a>
    </div></td><td class="field votes" style="display: none"><label>votes</label><div class="value">  <a href="/rating/voters/265364012?resource_type=Review">0</a>
    </div></td><td class="field read_count" style="display: none"><label># times read</label><div class="value">    0
    </div></td><td class="field date_started" style="display: none"><label>date started</label><div class="value">    <span class="greyText">not set</span>
        <a class="floatingBoxLink smallText" href="#" onclick="reviewEditor.summon(this, 12074927, 'started_at', {value: null}); return false;">[edit]</a>
    </div></td><td class="field date_read"><label>date read</label><div class="value">    <span class="greyText">not set</span>
        <a class="floatingBoxLink smallText" href="#" onclick="reviewEditor.summon(this, 12074927, 'read_at', {value: null}); return false;">[edit]</a>
    </div></td><td class="field date_added" style="display: none"><label>date added</label><div class="value">  <span title="January 21, 2012">
        Jan 21, 2012
      </span>
    </div></td><td class="field date_purchased" style="display: none"><label>date purchased</label><div class="value">    <a class="smallText" href="#" id="add_for_date_purchased" onclick="new Ajax.Request('/review/update/12074927?format=json', {asynchronous:true, evalScripts:true, onFailure:function(request){Element.hide('loading_anim_206609');$('add_for_date_purchased').innerHTML = '<span class=&quot;error&quot;>ERROR</span>try again';$('add_for_date_purchased').show();}, onLoading:function(request){;Element.show('loading_anim_206609');Element.hide('add_for_date_purchased')}, onSuccess:function(request){Element.hide('loading_anim_206609');Element.show('add_for_date_purchased');var json = eval('(' + request.responseText + ')');$('review_265364012').replace(json.html);if (typeof(toggleFieldsToMatchHeader) == 'function') {toggleFieldsToMatchHeader();}}, parameters:'owned_book[book_id]=12074927&amp;partial=bookalike&amp;view=table' + '&amp;authenticity_token=' + encodeURIComponent('J5JjYi/D31hPm9w3u8hM35umQTh8bK3md4dVzpi4eKQ=')}); return false;">(add)</a><img alt="Loading-trans" class="loading" id="loading_anim_206609" src="http://www.goodreads.com/assets/loading-trans-3e04cd6ed6ad31063972e688820d7866.gif" style="display:none">
    </div></td><td class="field owned" style="display: none"><label>owned</label><div class="value"></div></td><td class="field purchase_location" style="display: none"><label>purchase location</label><div class="value">    <a class="smallText" href="#" id="add_for_purchase_location" onclick="new Ajax.Request('/review/update/12074927?format=json', {asynchronous:true, evalScripts:true, onFailure:function(request){Element.hide('loading_anim_953979');$('add_for_purchase_location').innerHTML = '<span class=&quot;error&quot;>ERROR</span>try again';$('add_for_purchase_location').show();}, onLoading:function(request){;Element.show('loading_anim_953979');Element.hide('add_for_purchase_location')}, onSuccess:function(request){Element.hide('loading_anim_953979');Element.show('add_for_purchase_location');var json = eval('(' + request.responseText + ')');$('review_265364012').replace(json.html);if (typeof(toggleFieldsToMatchHeader) == 'function') {toggleFieldsToMatchHeader();}}, parameters:'owned_book[book_id]=12074927&amp;partial=bookalike&amp;view=table' + '&amp;authenticity_token=' + encodeURIComponent('J5JjYi/D31hPm9w3u8hM35umQTh8bK3md4dVzpi4eKQ=')}); return false;">(add)</a><img alt="Loading-trans" class="loading" id="loading_anim_953979" src="http://www.goodreads.com/assets/loading-trans-3e04cd6ed6ad31063972e688820d7866.gif" style="display:none">
    </div></td><td class="field condition" style="display: none"><label>condition</label><div class="value">    <a class="smallText" href="#" id="add_for_condition" onclick="new Ajax.Request('/review/update/12074927?format=json', {asynchronous:true, evalScripts:true, onFailure:function(request){Element.hide('loading_anim_990684');$('add_for_condition').innerHTML = '<span class=&quot;error&quot;>ERROR</span>try again';$('add_for_condition').show();}, onLoading:function(request){;Element.show('loading_anim_990684');Element.hide('add_for_condition')}, onSuccess:function(request){Element.hide('loading_anim_990684');Element.show('add_for_condition');var json = eval('(' + request.responseText + ')');$('review_265364012').replace(json.html);if (typeof(toggleFieldsToMatchHeader) == 'function') {toggleFieldsToMatchHeader();}}, parameters:'owned_book[book_id]=12074927&amp;partial=bookalike&amp;view=table' + '&amp;authenticity_token=' + encodeURIComponent('J5JjYi/D31hPm9w3u8hM35umQTh8bK3md4dVzpi4eKQ=')}); return false;">(add)</a><img alt="Loading-trans" class="loading" id="loading_anim_990684" src="http://www.goodreads.com/assets/loading-trans-3e04cd6ed6ad31063972e688820d7866.gif" style="display:none">
    </div></td><td class="field format"><label>format</label><div class="value"></div></td><td class="field actions"><label>actions</label><div class="value">    <div class="actionsWrapper greyText smallText">
          <div class="editLinkWrapper"><a class="actionLinkLite editLink" href="#" id="loading_link_818479" onclick="new Ajax.Request('/review/edit/12074927', {asynchronous:true, evalScripts:true, onFailure:function(request){Element.hide('loading_anim_818479');$('loading_link_818479').innerHTML = '<span class=&quot;error&quot;>ERROR</span>try again';$('loading_link_818479').show();}, onLoading:function(request){;Element.show('loading_anim_818479');Element.hide('loading_link_818479')}, onSuccess:function(request){Element.hide('loading_anim_818479');Element.show('loading_link_818479');}, parameters:'authenticity_token=' + encodeURIComponent('J5JjYi/D31hPm9w3u8hM35umQTh8bK3md4dVzpi4eKQ=')}); return false;">edit</a><img alt="Loading-trans" class="loading" id="loading_anim_818479" src="http://www.goodreads.com/assets/loading-trans-3e04cd6ed6ad31063972e688820d7866.gif" style="display:none"></div>
          <div class="viewLinkWrapper"><a href="/review/show/265364012" class="actionLinkLite viewLink nobreak">view »</a></div>
          <a href="/review/destroy/12074927?return_url=http%3A%2F%2Fwww.goodreads.com%2Freview%2Flist%2F4111865%3Fshelf%3Dto-read" class="actionLinkLite smallText deleteLink" data-confirm="Are you sure you want to remove The Fractal Prince from your books? This will permanently remove this book from your shelves, including any review, rating, tags, or notes you have added. To change the shelf this book appears on please edit the shelves." data-method="post" rel="nofollow">        <img alt="Remove from my books" src="http://www.goodreads.com/assets/layout/delete.gif" title="Remove from my books">
            <span class="label">remove book</span>
    </a>    </div>
    </div></td>
    </tr>
    
  • Mr Alpha
    Mr Alpha over 11 years
    This works mostly. The one problem is that the style is being applied to the div containing the date. I was looking to apply the style to the tr with the class .bookalike review that contain the dive with the date.
  • Brock Adams
    Brock Adams over 11 years
    Easily solved with parentNode. See the updated answer.
  • Mr Alpha
    Mr Alpha over 11 years
    Thank you! It works perfectly.
  • Brock Adams
    Brock Adams over 11 years
    You're welcome! Glad to help.