SitePoint Sponsor

User Tag List

Results 1 to 6 of 6
  1. #1
    SitePoint Member
    Join Date
    Apr 2006
    Posts
    7
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Object based xml request, object member scope issue..

    I know long code posts like this are hard to read...

    But this is really throwing me off why this doesn't work. Using this instantiation, I dont understand why I can't access this.targetDiv in the proccessReqChange function...

    I put two mad faces at the line where targetDiv is undefined, but should set to 'contentTable.

    var newRequest = new myXMLObj("contentTable", "index.cfm", "");
    newRequest.send();


    // this is my new xmlobj
    function myXMLObj(targDivIn, targUrlIn, postParamsIn){

    this.targetDiv = targDivIn; // this is the var I can't access
    this.targUrl = targUrlIn;
    this.postParams = postParamsIn;


    this.send = function()
    {
    //alert(this.targUrl);
    req = false;
    params = "";
    method = "GET";
    contentType = "application/x-www-form-urlencoded";

    if(window.XMLHttpRequest) {
    try {
    req = new XMLHttpRequest();
    }catch(e) {
    req = false;
    }
    }else if(window.ActiveXObject)
    {
    try {
    req = new ActiveXObject("Msxml2.XMLHTTP");
    } catch(e) {
    try {
    req = new ActiveXObject("Microsoft.XMLHTTP");
    } catch(e) {
    req = false;
    }
    }
    }
    if(req) {
    req.onreadystatechange = this.processReqChange;
    result = this.targUrl.match(/\?/gi);
    if(method == "GET")
    {
    if (result != null){
    req.open(method, this.targUrl + "&test=" + Math.random() , true);
    }else{
    req.open(method, this.targUrl + "?DD_test=" + Math.random() , true);
    }
    }else{
    req.open(method, this.targUrl, true);
    }
    if(contentType)
    {
    req.setRequestHeader("Content-Type", contentType);
    }
    //req.send(params);
    req.send("");
    }
    }

    this.processReqChange = function()
    {
    // only if req shows "loaded"
    if (req.readyState == 4) {
    // only if "OK"
    if (req.status == 200) {
    //alert('got call back, and we are ok !' + req.responseText);
    swapDivText(req.responseText, this.targetDiv);
    } else {
    alert ( "Error: " + req.status + " \n Text: " + req.statusText);
    }
    }
    }
    }


    As a side note, this is the swapDivTextfunction

    function swapDivText(text, id)
    {
    id = "contentTable";
    // I am forced to hard code the variable to swap becuase this.targetDiv
    // the variable is undefined in the "processReqchange that calls this function
    eval("divToSwap = document.getElementById('"+ id + "');");
    if(divToSwap)
    {
    if (divToSwap.innerHMTL != text)
    divToSwap.innerHTML = text;
    }
    else
    {
    alert("Unable to display some, or all, of the page content. We apologize for this, unable to locate div: " + id);
    }
    }

  2. #2
    SitePoint Wizard
    Join Date
    Mar 2001
    Posts
    3,537
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Always post code using code tags. See the thread "Read before you post" at the top of the forum.

  3. #3
    SitePoint Wizard silver trophy kyberfabrikken's Avatar
    Join Date
    Jun 2004
    Location
    Copenhagen, Denmark
    Posts
    6,157
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I'm a bit surprised that your function processReqChange even gets called, since you reference it before it's called. Nonetheless - The reason why this.targetDiv is undefined is because in javascript this refers to the calling context - not as you would expect from other languages, to the owner of the property. In javacript, functions are variables like anything else and so they can pe passed around and reference from multiple places. If you look at the following code, you can see that foo will have a different context, depending on how it was called:
    Code:
    var foo = function() {
        alert(this.name);
    };
    var a = new Object();
    var b = new Object();
    
    window.name = "window";
    a.name = "a";
    a.foo = foo;
    b.name = "b";
    b.foo = foo;
    
    // tests
    foo(); // alerts "window"
    a.foo(); // alerts "a"
    b.foo(); // alerts "b"
    
    // and a bit more complex
    function bar(fnc) {
        fnc();
    }
    bar(foo); // alerts "window"
    bar(a.foo); // alerts "window"
    The important lesson is that functions are not bound to objects. Objects are merely collections of functions.
    When you pass a function as a parameter, as you do in your code, you only pass the function - not the owner-object. Thus when the function is called, the context will not be your ownerobject.

    And the solution to the problem, once you understand it, is quite simple:
    Code:
    // req.onreadystatechange = this.processReqChange;
    var self = this; // put a reference to "this" in a local-scoped variable
    req.onreadystatechange = function() {
        // since the function is declared within the same scope as "self", it will be
        // available to it.
        self.processReqChange();
    };
    Since this is a trick, you will need to use a lot in javascript, I recommend that you automate it a bit :
    Code:
    // somewhere in the global scope
    window.bind = function(method, object) {
        return function() { return method.apply(object, arguments); };
    };
    
    ...
    
    // and within your code
    req.onreadystatechange = bind(this.processReqChange, this);

  4. #4
    SitePoint Member
    Join Date
    Apr 2006
    Posts
    7
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thank you much. I see what your saying, and your example, explination and then example code all helped very much.

    You must be like the java script god : ]

  5. #5
    SitePoint Wizard stereofrog's Avatar
    Join Date
    Apr 2004
    Location
    germany
    Posts
    4,324
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by kyberfabrikken
    Code:
    // somewhere in the global scope
    window.bind = function(method, object) {
        return function() { return method.apply(object, arguments); };
    };
    
    ...
    
    // and within your code
    req.onreadystatechange = bind(this.processReqChange, this);
    I think it's better to make bind() Function's member (see prototype's implementation)

  6. #6
    SitePoint Wizard silver trophy kyberfabrikken's Avatar
    Join Date
    Jun 2004
    Location
    Copenhagen, Denmark
    Posts
    6,157
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by stereofrog
    I think it's better to make bind() Function's member (see prototype's implementation)
    Messing with core prototypes makes me itchy. It's a matter of style though.


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •