www.webdeveloper.com
Recent Articles
  • Finding Slow Running Queries in ASE 15
  • A More Advanced Pie Chart for Analysis Services Data
  • Adobe AIR Programming Unleashed: Working with Windows
  • Performance Testing SQL Server 2008's Change Data Capture Functionality
  • The ABC's of PHP: Introduction to PHP
  • How to Migrate from BasicFiles to SecureFiles Storage
  • Why the Twitter Haters Are Wrong
  • User Personalization with PHP: Beginning the Application
  • Whats in an Oracle Schema?
  • Lighting Enhancement in Photoshop
  •  

    Go Back   WebDeveloper.com > Client-Side Development > JavaScript

    JavaScript JavaScript (not Java) Discussion and technical support, including AJAX and frameworks (JQuery, MooTools, Prototype...)

    Reply
     
    Thread Tools Search this Thread Rate Thread Display Modes
      #1  
    Old 11-19-2009, 01:55 PM
    catgirl catgirl is offline
    Registered User
     
    Join Date: Nov 2009
    Location: Canada
    Posts: 12
    resolved [RESOLVED] Help with scope on anonymous f'ns

    Hi all,

    What I am trying to do is write a function that submits an XMLHttpRequest and in the callback, call a function back on my caller and pass in all arguments that the submit function received.

    Perhaps it's easier to demonstrate:

    Code:
    function submitXMLHttpRequest(url, callbackFun /*, maybe other args here */)
    {
        var originalArgs = arguments;  // grab args so callback can pass them thru
        <snip>
        req.onreadystatechange = function (aEvt) {
    	if (req.readyState == 4)     
    	{
    	    if(req.status == 200)
    		callbackFun.call(req.responseText, originalArgs);
    	    else
         <snip>
    So I could call it like this in one script:
    Code:
    function makeXMLHttpRequest()
    {
           submitXMLHttpRequest(url, callbackFun1, onearg);
    }
    
    function callbackFun1(response, args)
    {
           var onearg= arguments[3];  // get back the arg sent in the make call
    }
    And in another script could call it like this:
    Code:
    function makeXMLHttpRequestAgain()
    {
          submitXMLHttpRequest(url, callbackFun2, somearg, anotherarg);
    }
    
    function callbackFun2(response, arguments)
    {
           var somearg= arguments[3];
           var anotherarg = arguments[4]; // get back both args sent in the make call
    }
    So basically I want to pass values from where I am calling the submit request through to the callback I want executed back in my script by passing them through the onreadystatechange callback but it's not working. The arguments parameter in my callbackFun1 and callbackFun2 are always undefined.

    Can someone help me understand why this doesn't work? I thought since the onreadystatechange is a closure, I have access to all of its enclosing scope, so shouldn't I have access to the original arguments passed into the submitXMLHttpRequest method so I can pass them through to the callback I desire? In some cases I have 3 parameters I need passed between methods, sometimes only 2, so instead of naming them, I wanted to pass via arguments.

    Thanks very much.
    Reply With Quote
      #2  
    Old 11-19-2009, 03:39 PM
    scragar's Avatar
    scragar scragar is offline
    Some Random Guy
     
    Join Date: Jun 2003
    Location: here
    Posts: 4,461
    Try using a wrapper.
    Code:
    req.onreadystatechange = (function(topArgs){// anything else you may need
    	return function (aEvt) {
    		if (req.readyState == 4){
    			if(req.status == 200)
    				topArgs[3].call(req.responseText, topArgs);
    			else
    ////..............
    	})(arguments);// close the wrapper
    __________________
    If you are using PHP please use the [php] and [/php] forum tags for highlighting...
    The same applies to HTML and the forums [html][/html] tags.
    Reply With Quote
      #3  
    Old 11-20-2009, 10:28 AM
    catgirl catgirl is offline
    Registered User
     
    Join Date: Nov 2009
    Location: Canada
    Posts: 12
    Interesting! I've only been doing Javascript a couple of months, I've not even seen that technique and will give it a try.
    Reply With Quote
      #4  
    Old 11-21-2009, 10:45 AM
    catgirl catgirl is offline
    Registered User
     
    Join Date: Nov 2009
    Location: Canada
    Posts: 12
    So I see where you are going with this scragar and I agree it should work but it doesn't. I've tried for hours without success. The desired callback function gets called but any arguments I have passed to it seem to be null. I can log the response in my readystatechange callback to ensure that I have one, then pass it to my callback that I trigger in the call statement and when I get there it's null.

    Thanks for your help though, and for introducing me on to this technique.
    Reply With Quote
      #5  
    Old 11-21-2009, 10:51 AM
    scragar's Avatar
    scragar scragar is offline
    Some Random Guy
     
    Join Date: Jun 2003
    Location: here
    Posts: 4,461
    Can you show me the code you are using? The code I posted should work, but since you had to edit it I understand how it's only too easy to remove something simple.
    Also, if you get any error messages it might be worth posting those.
    __________________
    If you are using PHP please use the [php] and [/php] forum tags for highlighting...
    The same applies to HTML and the forums [html][/html] tags.
    Reply With Quote
      #6  
    Old 11-21-2009, 11:10 AM
    catgirl catgirl is offline
    Registered User
     
    Join Date: Nov 2009
    Location: Canada
    Posts: 12
    He he, dedicated guy, workin' on a Saturday!

    Ok here it is and I've noticed something strange which I will point out after the code:

    calling script

    Code:
      function doSomethingInteresting()
      {
          var url = "www....";
          var threadId = "1234567";
          submitXMLHttpRequest(url, testFunction, threadId);
      }
    
      function testFunction(response, passThroughArguments)
     {
        log (response);
     }
    script that's got the submit method in it:

    Code:
    function submitXMLHttpRequest(url, callbackFun)
    {
         var req = new XMLHttpRequest();
         req.open("GET", url, true);
         req.onreadystatechange = (function (passThruArgs) {
    	return function (aEvt) {
    		if (req.readyState == 4)        
    		{
    		    if(req.status == 200)
    		    {
    			log (req.responseText);
    			passThruArgs[1].call(req.responseText, passThruArgs);
    		    }
    		    else
    			log ('request for message ' + url + ' failed);
    		}
    	};  // end callback function
        })(arguments); // end wrapper function and execute it immediately to preserve scope
    
        req.send(null);
    }
    And what I am noticing is strange is if I put a breakpoint in my callback function, in testFunction, the first argument, response, has the pass through arguments in it, and the second argument, passThroughArguments, is null. The args seem to be displaced by 1 and I don't get the response at all. When I log the responseText in onreadystatechange before making the call call it looks exactly as it should.

    I have tried not passing the passThruArgs from onreadystatechange at all, so like this
    Code:
        passThruArgs[1].call(req.responseText);
    but the function argument in testFunction is still null so it's not the passing thru of args that's screwing it up.

    I also tried passing the request in to the scope preserving function, so this:

    Code:
            };  // end callback function
        })(req, arguments);
    and that didn't work either.
    Reply With Quote
      #7  
    Old 11-21-2009, 11:39 AM
    Scriptage Scriptage is offline
    Registered User
     
    Join Date: Nov 2002
    Location: England
    Posts: 680
    You need to use apply: callbackFun.apply(this, originalArgs).
    Reply With Quote
      #8  
    Old 11-21-2009, 11:43 AM
    catgirl catgirl is offline
    Registered User
     
    Join Date: Nov 2009
    Location: Canada
    Posts: 12
    Hmmm, I thought because I was passing an array either call or apply would work...?
    Reply With Quote
      #9  
    Old 11-21-2009, 11:53 AM
    Scriptage Scriptage is offline
    Registered User
     
    Join Date: Nov 2002
    Location: England
    Posts: 680
    No, use call for named parameters, use apply when sending an array object: https://developer.mozilla.org/En/Cor...Function/Apply
    Reply With Quote
      #10  
    Old 11-21-2009, 12:19 PM
    catgirl catgirl is offline
    Registered User
     
    Join Date: Nov 2009
    Location: Canada
    Posts: 12
    Ah ok I read that, and interpreted it as if I wanted to pass a whole array I use apply, if I wanted to pass in individual args I could use call but that one of those args could be an array. Ok, I am clear on that now.

    But I tried what you suggested, that's not working for me either.

    onreadystatechange function now says:
    Code:
         log ('passthruargs length is ' + passThruArgs.length);
         log (req.responseText);
         passThruArgs[1].apply(this, passThruArgs);
    If my testFunction is as follows:

    Code:
    function testFunction(response, args)
    {
        log ('response is ' + response.responseText);
        log ('args length is ' + args.length);
        log ('args 0 is ' + args[0]);
        log ('args 1 is ' + args[1]);
        log ('args 2 is ' + args[2]);
    }
    The output I get from this is:

    passthruargs length is 3
    the responseText
    response is undefined
    args length is 2
    args 0 is <url i passed in>
    args 1 is <entire definition of the testFunction function>
    args 2 is undefined

    So I'm not getting the response text and the third argument which are really the two things I need to be getting into my callback.
    Reply With Quote
      #11  
    Old 11-21-2009, 01:00 PM
    Scriptage Scriptage is offline
    Registered User
     
    Join Date: Nov 2002
    Location: England
    Posts: 680
    I see what's happening now:

    var originalArgs = arguments; // grab args so callback can pass them thru
    <snip>
    req.onreadystatechange = function (aEvt) {
    if (req.readyState == 4)
    {
    if(req.status == 200)
    callbackFun.apply(this, originalArgs.splice(0,2, req.responseText));


    That will remove the first two elements of originalArgs and add responseText to the start of the array. That should do the trick.
    Reply With Quote
      #12  
    Old 11-21-2009, 01:09 PM
    Scriptage Scriptage is offline
    Registered User
     
    Join Date: Nov 2002
    Location: England
    Posts: 680
    So the reponse text is the first argument, then all additional arguments start at index 1.
    Reply With Quote
      #13  
    Old 11-21-2009, 01:46 PM
    catgirl catgirl is offline
    Registered User
     
    Join Date: Nov 2009
    Location: Canada
    Posts: 12
    Hm, ok, so you have me going back to the original code I had, not the code that was suggested by scragar to wrap the onreadystatechange anonymous in order to capture the state from the outer.

    Ok, I will try going back to what I had originally with the mods you have suggested
    Reply With Quote
      #14  
    Old 11-21-2009, 02:26 PM
    catgirl catgirl is offline
    Registered User
     
    Join Date: Nov 2009
    Location: Canada
    Posts: 12
    Ok close but no cigar. I get the error 'originalArgs.splice is not a function'. I think that's because arguments is an array-like object, but not an instance of array, isn't it? So I can't use array functions on it.
    Reply With Quote
      #15  
    Old 11-21-2009, 02:35 PM
    Scriptage Scriptage is offline
    Registered User
     
    Join Date: Nov 2002
    Location: England
    Posts: 680
    Sorry, try this:

    var originalArgs = Array.prototype.slice.call(arguments);
    Reply With Quote
    Reply

    Bookmarks


    Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
     
    Thread Tools Search this Thread
    Search this Thread:

    Advanced Search
    Display Modes Rate This Thread
    Rate This Thread:

    Posting Rules
    You may not post new threads
    You may not post replies
    You may not post attachments
    You may not edit your posts

    BB code is On
    Smilies are On
    [IMG] code is Off
    HTML code is Off
    Forum Jump


    All times are GMT -5. The time now is 03:38 PM.



    Acceptable Use Policy


    The Network for Technology Professionals

    Search:

    About Internet.com

    Legal Notices, Licensing, Permissions, Privacy Policy.
    Advertise | Newsletters | E-mail Offers

    Powered by vBulletin® Version 3.7.3
    Copyright ©2000 - 2010, Jelsoft Enterprises Ltd.