Jump to content

Out of Scope/ improperly referenced?


xtopolis

Recommended Posts

I can't figure out why I can't access the object properties in my function addTime().  The object (dayObject) is created with properties: src, name, hoursArr, counter.  (src is the parent element (HTML obj), name (str), hoursArr(array), counter(int).

 

It calls itself with init(), which is a function that is prototyped to the dayObject.  Inside of dayObject->init(), those properties are still visible (alert(this.name))...  When I later called addTime() (which is an onclick event), it no longer sees those properties (they are undefined..)  Anyone know why?

 

[if I had to guess what was wrong, I'd say that in the init() function, the binding of link.onclick = this.addTime doesn't provide a reference to the object itself...  I'm not sure how to provide it though, using this coding style (which I'd like to stick with)]

 

HTML for testing:

<html><head></head><body>
<div id="timezones">
    <div class="Monday" id=div_Monday"></div>
    <div class="Tuesday" id="div_Tuesday"></div>
</div><!-- timezones -->
<script type="text/javascript" src="times.js"></script>
</body></html>

 

relevant Javascript (times.js)

var hours = [ "--",1,2,3,4,5,6,7,8,9,10 ];//available hours
var dayObjTracker = [];


//onload bind to divs
window.onload = function () {
    //get div for each day
    var tz = document.getElementById("timezones");
        var target_divs = tz.getElementsByTagName("div");
    
    //create day object for each day
    for(var i=0;i<target_divs.length;i++)
    {
        dayObjTracker.push( new dayObject(target_divs[i]) );
    }
}//onload ---------------------------------------------------


//dayObject
function dayObject(mainElement) {

    this.src = mainElement;
    this.name = mainElement.className;
    this.hoursArr = hours.slice();
    this.counter = 0;

        this.init();
};//dayObject -----------------------------------------------


//init(): add links to the divs
dayObject.prototype.init = function() {
    //create the link + attributes
    var link = document.createElement("a");
        link.appendChild(document.createTextNode("Add Time"));//link text
        link.setAttribute("href", "#");//null href
        link.onclick = this.addTime;//onclick
    
    //append link to main element
    this.src.appendChild(link);
}//init -----------------------------------------------------


//addTime(): request a new time block
dayObject.prototype.addTime = function() {
    alert(this.counter);  //this comes up as undefined ##
}

Link to comment
https://forums.phpfreaks.com/topic/171860-out-of-scope-improperly-referenced/
Share on other sites

I don't have any event handler code..  What I provided is exactly what I had up to that point.. The rest of the code that is missing would include creating SELECT and OPTION elements, and appending them to the source element..  I didn't include the addTime() code before because it is reliant on having access to the this.hoursArr variable.

 

Perhaps I misunderstand your question?

 

The HTML code is exactly the same.

 

The full javascript is this:

var hours = [ "--",1,2,3,4,5,6,7,8,9,10 ];//available hours
var dayObjTracker = [];


//onload bind to divs
window.onload = function () {
    //get div for each day
    var tz = document.getElementById("timezones");
        var target_divs = tz.getElementsByTagName("div");
    
    //create day object for each day
    for(var i=0;i<target_divs.length;i++)
    {
        dayObjTracker.push( new dayObject(target_divs[i]) );
    }
}//onload ---------------------------------------------------


//dayObject
function dayObject(mainElement) {

    this.src = mainElement;
    this.name = mainElement.className;
    this.hoursArr = hours.slice();
    this.counter = 0;

        this.init();
};//dayObject -----------------------------------------------


//init(): add links to the divs
dayObject.prototype.init = function() {
    //create the link + attributes
    var link = document.createElement("a");
        link.appendChild(document.createTextNode("Add Time"));//link text
        link.setAttribute("href", "#");//null href
        link.onclick = this.addTime;//onclick
    
    //append link to main element
    this.src.appendChild(link);
}//init -----------------------------------------------------


//addTime(): request a new time block
dayObject.prototype.addTime = function() {

    //create paragraph to hold it
    var p = document.createElement("p");
        p.setAttribute("id","timeblock_" + this.counter);
    
    //create "From"
    var fromTxt = document.createElement("span");
        fromTxt.setAttribute("class","fromText");
        fromTxt.appendChild(document.createTextNode("From"));

    //create "until"
    var fromTxt = document.createElement("span");
        fromTxt.setAttribute("class","untilText");
        fromTxt.appendChild(document.createTextNode("until"));

    //#############
    //create select1: name == day_start/end# (Monday_start0...)
        var startName = this.name + "_" + "start" + this.counter;
        var endName = this.name + "_" + "end" + this.counter;

    var select1 = makeSelect(startName, this.hoursArr, endName);
        
        //if its the first one, make it reset all others
        if(this.counter == 0) {
            select1.onchange = function() {
                alert('ready to remove all');
                updateOps(select1, endName);//source Element, destination name
            }
        }else{
            select1.onchange = function() {
                updateOps(select1, endName);
            }
        }//counter == 0?
        
    //create select2
    var select2 = makeSelect(endName, this.hoursArr, "");
    
    
        //put it together
        p.appendChild(fromTxt);
        p.appendChild(select1);
        p.appendChild(untilTxt);
        p.appendChild(select2);
        
        this.src.appendChild(p);

}//addTime --------------------------------------------------
*/

//makeSelect(): create a <select> element
function makeSelect(name, hoursArr, trgt) {

    //create select element
    var select = document.createElement("select");
        select.setAttribute("name", name);
        select.setAttribute("id", name);
        select.setAttribute("trgt",trgt);//trgt is second select in block or null
    
    var opsArr = makeOptions(hoursArr);
        var opsArr_len = opsArr.length;
    
    for(var i=0; i<opsArr_len; i++)
    {
        select.appendChild(opsArr[i]);
    }
    
    return select;//HTML element
}//makeSelect -----------------------------------------------


//makeOptions: create <option> element(s)
function makeOptions(arr) {

    var ops = [];
    var arr_len = arr.length;
    for(var i=0; i<arr_len; i++)
    {
        var o = document.createElement("option");
            o.setAttribute("value", arr[i]);//val
            o.appendChild(document.createTextNode(arr[i]));//innerhtml
        ops.push(o);
    }
    
    return ops;//array
}//makeOptions ----------------------------------------------

//updateOps: change all elements to be higher than previous select
function updateOps(src,dest) {

    var hrs = hours.slice(src.selectedIndex + 1);
    var trgt = document.getElementById(dest);
        while(trgt.hasChildNodes() && (trgt.childNodes.length >= 1)) {
            trgt.removeChild( trgt.firstChild );
        }
    var o = makeOptions(hrs);
        var o_len = o.length;
    for(var i=0;i<o_len;i++)
    {
        trgt.appendChild(o[i]);
    }
}//updateOps ------------------------------------------------

Oh, I see the problem.  Your assumption is correct - the 'this' in addDate is referencing the link, not your custom object.  Why cant you just pass a reference of the object to the function?  Something like:

 

dayObject.prototype.addDate = function(objRef){
   alert(objRef.counter);
}

//in init():

link.onclick = addDate(this);

Thanks, I was able to get it to recognize the object using your suggestion.  It also brought along another issue, see below.

//init();
        ...
        link.onclick = this.addTime(this);//onclick

//addTime();
dayObject.prototype.addTime = function(objRef) {//I had tried this,placing "this" instead of objRef or w.e inside >.> so close..
        alert(objRef.counter);
}

 

 

However, in changing the init() onclick line, it now automatically executes the function on page load.  addTime(this) runs without clicking, etc, and clicking on the link doesn't do anything.  I have had this problem before, but not sure how I fixed it.. any ideas?  I will continue to mess around with it as well.

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.