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 >>>> >>>> >>>> >>>> >>>> >>> >>> >> > >