Hi Nate,  Thanks again for your reply.  You've supplied some good 
resources and explanations, and I'm getting a better understanding.  
However, each time I 'think' I've got it, I come across a situation that 
just proves I don't.  It's going to be a struggle, but I'm determined to 
get to the 'penny drops' moment.

Thanks again.

Glenn

Nate Cavanaugh wrote:
> Hi Glenn,
> Closures are a pretty tough concept to fully explain. In this case, I should
> have just said to use an "anonymous function", as it would probably lead to
> less confusion.
> Here is a great online resource about closures that really helped me a lot:
> http://www.hunlock.com/blogs/Closing_The_Book_On_Javascript_Closures
>
> About the mechanism of this:
>
> This always points to the current object that it's running in, except in two
> cases: when it's pointing to the element that executed an action, or it is
> explicitly set to something different.
>
> I'll give you a good example:
>
> var obj = {
>       init: function() {
>               var instance = this; // points to obj
>               
>               var obj2 = {
>                       run: function() {
>                               var instance = this; // points to obj2
>                       }
>               };
>               
>               $('a').click(
>                       function(e) {
>                               var item = this; // points to the element that 
> was clicked
>                       }
>               );
>               
>               obj2.run.call(instance); // now obj2.run is called, it's own 
> 'this' points
> to obj instead of obj2
>       }
> };
>
> That piece of code covers the different situations I was talking about.
>
> The 'call' method explicitly overrides the this in obj2 with a new obj, and
> 'this' now points to the object passed in.
>
> But in every other case, this points to the current object that it's
> existing in.
>
> By the way, to limit confusion a bit, your code, even though it was
> functions, in Javascript those functions are objects as well, so the scoping
> applies.
>
> I hope that helps clear things up, but if not, feel free to ask away :)
>
>
> knnelg wrote:
>   
>> Hi Nate,
>>
>> First of all, thank you very much for taking the time to respond.  It's 
>> greatly appreciated.
>>
>> I had to modify your solution slightly, in that the ajax.complete 
>> callback passes two parameters which I need, so I changed the code to...
>>
>> var instance = this;
>>
>> $.ajax(
>>
>>     {
>>         type: "POST", // type of http request
>>         url: this.sourceURL, // where to get file from
>>         dataType: "xml", // type of file to retrieve
>>         complete: function(ajaxResponse, status){
>>             instance.parseXML(ajaxResponse, status);
>>         }
>>     }
>> );
>>
>> This works just fine, and I thank you once again.  I'd never have worked 
>> this out using the books I have.
>>
>> I have to admit though, I still don't fully understand the mechanism 
>> going on here.  If anyone is aware of any on-line resources that go into 
>> detail about the scope of 'this', I'd be grateful.
>>
>> You mention the phrase "you can use a closure", is this a common term in 
>> Javascript? What does it mean?
>>
>> Once again, thank you.
>>
>> Regards,
>>
>> Glenn
>>
>>
>>
>> Nate Cavanaugh wrote:
>>     
>>> Hi Glenn,
>>> Keeping scope is definitely one of the more frustrating aspects of
>>> Javascript sometimes.
>>>
>>> What's happening is that you're running the ajax call, and the complete
>>> method is a method of the object that you're passing into the ajax
>>> handler.
>>>
>>> So this now points to the object containing the properties you sent in.
>>>
>>> To do this so that your member method (the this.parseXML) retains the
>>> proper
>>> scope, you can use a closure. I also like to always start off my methods
>>> with a var declaration pointing to the instance this (so I always know
>>> when
>>> I am pointing to the instance, and when I use this, that I am pointing to
>>> an
>>> element, such as in an event call back):
>>>
>>> var instance = this;
>>>
>>> $.ajax(
>>> {
>>> type: "POST", // type of http request
>>> url: this.sourceURL, // where to get file from
>>> dataType: "xml", // type of file to retrieve
>>> complete: function(){
>>> instance.parseXML();
>>> }
>>> }
>>> );
>>>
>>> Now your parseXML method will run in the proper scope.
>>>
>>> I hope that helps :)
>>>
>>>
>>> knnelg wrote:
>>>   
>>>       
>>>> Hi,  I'm another newbie to jQuery and also not that experienced in
>>>> JavaScript so I'm not sure if my issue is jQuery or JavaScript.
>>>>
>>>> The issue is that I'm creating a constructor for an object, in which I
>>>> initialise some instance properties, then kick off an asynchronous
>>>> $.ajax event to retrieve an XML file.  The callback method of
>>>> the .ajax object is bound to a prototype method of the same object as
>>>> the constructor.
>>>>
>>>> My problem is that when the ajax call is complete and the callback
>>>> method is called, it appears that the callback method cannot see any
>>>> of the 'this'.properties that were initialized in the constructor.
>>>>
>>>> I'm beginning to think that the asynchronous nature of the ajax object
>>>> has actually created a new instance of my object in which no
>>>> constructor was called and therefore is not working against the
>>>> original instance I created.  But then again I always look for the
>>>> most obscure explanation instead of noticing the simple error I've
>>>> made.
>>>>
>>>> I've included the code below.  If anyone can show me the errors of my
>>>> ways, I'd be very grateful.
>>>>
>>>> The line causing me a problem is commented with // THIS LINE FAILS
>>>> WITH AN "this.woffers has no properties" ERROR
>>>>
>>>> ================================================================
>>>> // Use jQuery 'document.ready' selector to define the function to call
>>>> when page is ready.
>>>> $(main);
>>>>
>>>> //////////////////////////////////////////////////////////////////////////////
>>>> // The main entry function hopefully called by the jQuery 'ready'
>>>> selector
>>>> //////////////////////////////////////////////////////////////////////////////
>>>> function main() {
>>>>
>>>>    try {
>>>>            //create a new 'Woffers' instance
>>>>            var woffers = new Woffers("woffersdata.xml", "xml");
>>>>    }
>>>>
>>>>    // Catch any exceptions...
>>>>    catch(e) {
>>>>
>>>>            // ...and report them.  TODO: remove this for live
>>>>            alert(e);
>>>>
>>>>    }
>>>>
>>>> }
>>>>
>>>> //////////////////////////////////////////////////////////////////////////////
>>>> // Constructor for a 'Woffers' class which will contain all our
>>>> 'Woffer' items
>>>> // and some methods to retrieve them.
>>>> //
>>>> // Expects:
>>>> // sourceURL - a String containing the location of the file containing
>>>> the
>>>> //         data to be used to construct our object.
>>>> // sourceType - a String containing the type of file we are using to
>>>> //         construct the object.  Can be "xml" or "json"
>>>> //////////////////////////////////////////////////////////////////////////////
>>>> function Woffers(sourceURL, sourceType) {
>>>>    if(sourceType != "xml") {
>>>>            throw new Error("Invalid source type (" + sourceType + ") 
>>>> supplied
>>>> to Woffers constructor.");
>>>>    }
>>>>
>>>>    // Store parameters for later use by any method
>>>>    this.sourceURL = sourceURL;
>>>>    this.sourceType = sourceType;
>>>>
>>>>    // Create a property to hold a list of Woffer objects
>>>>    this.woffers = new Array(); // <-- This property should get populated
>>>> by the $.ajax callback method
>>>>
>>>>    switch(this.sourceType) {
>>>>            case "xml": {
>>>>                    $.ajax(
>>>>                            {
>>>>                                    type: "POST", // type of http request
>>>>                                    url: this.sourceURL, // where to get 
>>>> file from
>>>>                                    dataType: "xml", // type of file to 
>>>> retrieve
>>>>                                    complete: this.parseXML // Function to 
>>>> run on completion which
>>>> will populate this.woffers
>>>>                            }
>>>>                    )
>>>>
>>>>                    break;
>>>>
>>>>            } // End case(xml)
>>>>
>>>>            case "json": {
>>>>                    $.ajax(
>>>>                            {
>>>>                                    type: "POST", // type of http request
>>>>                                    url: this.sourceURL, // where to get 
>>>> file from
>>>>                                    dataType: "json", // type of file to 
>>>> retrieve
>>>>                                    complete: this.parseJson // Function to 
>>>> run on completion
>>>>                            }
>>>>                    )
>>>>
>>>>                    break;
>>>>
>>>>            } // End case(json)
>>>>    }
>>>>
>>>> } // End Woffers constructor
>>>>
>>>> //////////////////////////////////////////////////////////////////////////////
>>>> //
>>>> //////////////////////////////////////////////////////////////////////////////
>>>> Woffers.prototype.parseXML = function(woffersDOM, resultStatus) {
>>>>    if(resultStatus != "success") {
>>>>            throw new Error("Encountered a problem retreiving the XML 
>>>> file." +
>>>>                                            " Reported status is " + 
>>>> ResultStatus + ".");
>>>>    }
>>>>    // retrieve a list of woffers from the response
>>>>    var retrievedWoffers =
>>>> woffersDOM.responseXML.documentElement.getElementsByTagName("route");
>>>>
>>>>    // Go through each woffer and use it to create a new 'Woffer' object
>>>>    for(var index = 0; index < retrievedWoffers.length; ++index) {
>>>>
>>>>         //
>>>>         // THIS LINE FAILS WITH AN "this.woffers has no properties"
>>>> ERROR
>>>>         //
>>>>         // Create a new woffer and add it to 'this.woffers'
>>>>         this.woffers.push(new Object());
>>>>
>>>>    }
>>>>
>>>> }
>>>>
>>>>
>>>> Any feedback, much appreciated
>>>>
>>>> Regards,
>>>>
>>>> Glenn
>>>>
>>>>
>>>>
>>>>     
>>>>         
>>>   
>>>       
>>     
>
>   

Reply via email to