Adding elements to the DOM using appendChild then referring back to the class that created them

How do you go around adding an element to the DOM which still knows which instance of an object created it so that it can refer back to the class later on?

Basically the following code should allow you to add one or more photo albums to a page, where Javascript generates all the DOM elements needed.

I.e. in the following code example it would just take five lines of code (on top of the includes) - the HTML and three JS init lines.

If I add a button with the onclick event of pa.fwd() it pages to the correct element, but obviously I don't know what the "pa" variable will be. I have tried this - no use as it prefers to the div I am clicking on. I have tried parent, again no use as it travels up the DOM.

(i.e. what would I need to put in the next_btn.onclick line for it to execute pa.fwd() at run time, or pa2.fwd() or fotos.fwd() depending on the parent variable?)

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>Photo Album Demo</title>
    <style type="text/css">
    /* CSS Style Declarations */
    </style>
    <script type="text/javascript">
    // <![CDATA[

    // Noddy Functions
    function showDiv(divname)
    {
        document.getElementById(divname).style.display = "block";
        document.getElementById(divname).style.visibility = "visible";
    }

    function hideDiv(divname)
    {
        document.getElementById(divname).style.display = "none";
        document.getElementById(divname).style.visibility = "hidden";
    }   

    /* -- [[ Photo Album Class ]] -- */
    var kjsPhotoAlbum_prev_button = "/libs/prev.png";
    var kjsPhotoAlbum_next_button = "/libs/next.png";
    function kjsPhotoAlbum(_container_id,_width,_height) 
    {
        var photos = new Array();
        var width = _width;
        var height = _height;
        var parent_container = _container_id;
        var imageCache = new Array();
        var photo_index = 0;

        var obj = function(id) { return document.getElementById(id); }

        this.addPhoto = function(_filename,_caption)
        {
            photos[photos.length] = new Object({fn:_filename,c:_caption});
            imageCache[photos.length-1] = new Image();
            imageCache[photos.length-1].src = _filename; 
        }

        this.initalise = function()
        {
            obj(parent_container).className = 'kjsPhotoAlbum';
            obj(parent_container).style.width = width + "px";
            obj(parent_container).style.height = height + "px";

            var caption_bar = document.createElement("div");
            caption_bar.id = parent_container + "_caption";
            caption_bar.className = 'kjsPhotoAlbumCaption';
            caption_bar.style.position = "absolute";
            document.getElementById(parent_container).appendChild(caption_bar);

            var image_box = document.createElement("img");
            image_box.id = parent_container + "_image";
            image_box.className = 'kjsPhotoAlbumImage';
            image_box.style.position = "absolute";
            image_box.src = '/libs/1px.gif';
            document.getElementById(parent_container).appendChild(image_box);

            var next_btn = document.createElement("div");
            next_btn.id = parent_container + "_next";
            next_btn.className = 'kjsPhotoAlbumNext';
            next_btn.style.position = "absolute";
            next_btn.onmousemove = function(e) { showDiv(parent_container + "_next_image"); }
            next_btn.onmouseout = function(e) { hideDiv(parent_container + "_next_image"); }
            next_btn.onclick = function(e) { this.fwd(); }
            /* HOW DO I GET THIS TO KNOW THAT IT WAS GENERATED FROM THE PA */

            document.getElementById(parent_container).appendChild(next_btn);

            var next_btn_img = document.createElement("img");
            next_btn_img.id = parent_container + "_next_image";
            next_btn_img.className = 'kjsPhotoAlbumNextImage';
            next_btn_img.style.position = "absolute";
            next_btn_img.src = kjsPhotoAlbum_next_button;
            document.getElementById(next_btn.id).appendChild(next_btn_img);

            var prev_btn = document.createElement("div");
            prev_btn.id = parent_container + "_prev";
            prev_btn.className = 'kjsPhotoAlbumPrev';
            prev_btn.style.position = "absolute";
            document.getElementById(parent_container).appendChild(prev_btn);

            var prev_btn_img = document.createElement("img");
            prev_btn_img.id = parent_container + "_prev_image";
            prev_btn_img.className = 'kjsPhotoAlbumPrevImage';
            prev_btn_img.style.position = "absolute";
            prev_btn_img.src = kjsPhotoAlbum_prev_button;
            document.getElementById(prev_btn.id).appendChild(prev_btn_img);
        }

        this.play = function()
        {
            if (photos.length > 0)
            {
                this.show(0);
            }
            else
            {
                alert("Unable to play, no photos exist");
            }
        }

        this.resizeImage =function(idx)
        {
            var ratio = 1;
            var new_w = width;
            var new_h = height;
            var src_w = imageCache[idx].width;
            var src_h = imageCache[idx].height;
            ratio = Math.min( new_w / src_w, new_h / src_h );
            new_w = ratio * src_w;
            new_h = ratio * src_h;
            obj(parent_container + "_image").style.width        = new_w + "px";
            obj(parent_container + "_image").style.height       = new_h + "px";
            obj(parent_container + "_image").style.marginLeft   = (0-(new_w/2)) + "px";
            obj(parent_container + "_image").style.marginTop    = (0-(new_h/2)) + "px";
        }

        this.show = function()
        {
            obj(parent_container + "_image").src            = photos[photo_index].fn;
            obj(parent_container + "_caption").innerHTML    = "<span>" + photos[photo_index].c + "</span>";
            this.resizeImage(photo_index);
        }


        this.fwd = function()
        {
            if (photo_index < photos.length)
            {
                photo_index++;
                this.show(photo_index);
            }
        }

        this.initalise();
    }

    /* -- [[ End Class ]] ---------------------------------------------------- */
    var pa;
    function init()
    {
        pa = new kjsPhotoAlbum('PhotoAlbum',800,500);
        pa.addPhoto("/libs/1.jpg","Caption 1");
        pa.addPhoto("/libs/2.jpg","Caption 2");
        pa.addPhoto("/libs/3.jpg","Caption 3");
        pa.addPhoto("/libs/4.jpg","Caption 4");
        pa.addPhoto("/libs/5.jpg","Caption 5");
    }
    // ]]>
    </script>
</head>

<body onload="init()">
    <div id="PhotoAlbum"></div>
</body>
</html>
13.10.2009 16:10:39
1 ОТВЕТ
РЕШЕНИЕ

You need to capture the instance of kjsPhotoAlbum (available as this) inside a variable, and reference that variable inside your click handler code:

var that = this;
next_btn.onclick = function(e) { that.fwd(); }

This is a JavaScript closure.

3
13.10.2009 16:23:44
Thanks - that does exactly what I required :o)
Kev 13.10.2009 16:22:55