Detecting when the contents of a web page changes

Posted on

Problem

This is the code I’m using at the moment

/*
 * Adjust content height so that it always fills browser height
 *
 * written by Tom Jenkinson
 */

jQuery(document).ready(function() {

    refreshContentSize(); //run initially

    $(window).resize(function() { //run whenever window size changes
        refreshContentSize();
    });

    setInterval('refreshContentSize()', 500); // in case content size changes. THIS IS WHAT I WANT TO CHANGE
});

function refreshContentSize()
{
    var startPos = $("#content").position();
    var topHeight = startPos.top;
    var contentHeight = $("#content").outerHeight(true);
    var footerHeight = $("#footer").outerHeight(true);
    var viewportHeight = $(window).height();    
    var spaceForContent = viewportHeight - footerHeight - topHeight;

    if (spaceForContent <= contentHeight)
    {
        var newHeight = 0;
    }
    else
    {
        var newHeight = spaceForContent - contentHeight;
    }
    $("#filler").css('height', newHeight);
    return; 
}

The site is http://wncba.co.uk/results and the script is at http://wncba.co.uk/results/javascript/fill-pagev2.js.

At the moment you can see that I’m using a timer to keep calling the refreshContentSize(). I am doing this because some of the content on the page can change dynamically meaning the page height will change.

Is there a handle for this like jquery’s ‘resize’ so I don’t need the timer?

Solution

I can’t really verify what the code does since when I checked, the filler is always 0px. But I assume your code checks for the surrounding elements in an interval and updates the filler height accordingly.

I have some tips for your code:

//shorthand .ready using the jQuery namespace
//and using the $ as the inner namespace
jQuery(function ($) {

    //cache repeatedly used references
    var content = $("#content"),
        footer = $("#footer"),
        $window = $(window),
        filler = $("#filler");

    // - place functions inside the ready handler to avoid globals
    // - always hand over a function reference to a timer and never an eval-able string
    // - since 500ms is fast enough, resize and an init wouldn't be needed
    //   a human sees 200ms as "instant" and at least 700ms a significant lag
    //   somewhere in between is the "sweet spot"
    setInterval(function () {
        var startPos = content.position(),
            topHeight = startPos.top,
            contentHeight = content.outerHeight(true),
            footerHeight = footer.outerHeight(true),
            viewportHeight = $window.height(),
            spaceForContent = viewportHeight - footerHeight - topHeight,
            //JS has a function scope. Any variable declared anywhere is visible
            //everywhere in the containing function. Therefore, it's better to
            //declare them outside operations
            newHeight = 0; //default to 0

        //overwrite 0 if conditions state otherwise
        if (spaceForContent > contentHeight) {
            newHeight = spaceForContent - contentHeight
        }

        //so it's 0 or some other value
        filler.css('height', newHeight);

    }, 500);
});

Packed version:

jQuery(function ($) {
    var content = $("#content"),
        footer = $("#footer"),
        $window = $(window),
        filler = $("#filler");
    setInterval(function () {
        var startPos = content.position(),
            topHeight = startPos.top,
            contentHeight = content.outerHeight(true),
            footerHeight = footer.outerHeight(true),
            viewportHeight = $window.height(),
            spaceForContent = viewportHeight - footerHeight - topHeight,
            newHeight = 0;
        if (spaceForContent > contentHeight) {
            newHeight = spaceForContent - contentHeight
        }
        filler.css('height', newHeight)
    }, 500)
});

You might want to check out Mutation Observers API which gives you the ability to listen to changes in the DOM. It’s not yet supported across browsers but just included it if ever you are interested.

Also, I think it’s better that you rethink your layout – one which only relies on plain HTML and CSS.

Leave a Reply

Your email address will not be published. Required fields are marked *