SitePoint Sponsor

User Tag List

Results 1 to 19 of 19
  1. #1
    SitePoint Member
    Join Date
    Oct 2010
    Posts
    6
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Smile Cannot call a user defined JS function after return the AJAX content

    I am having a problem of calling the user defined JS function after I make the AJAX call. Basically, I created couple radio buttons on the main html page. When the user clicks on one of the radio button, it will trigger the AJAX call and return another html file in the "div" content that I set in the main html page. The other html file contains a user defined JS function (e.g. "updateContent()") which use the onclick event handler to call the function. When I'm running the app, and click on the button. I had seen the firebug was complaining the "updateContent() is not defined" error. The function itself works fine and must be defined properly. Please help me about this! Thanks.

    Here is the code in the main.html page:
    Code:
    <script type="text/javascript">
      var asyncRequest;
    	function getTools(url){
      	 try
             {
    		asyncRequest = new XMLHttpRequest();
    		asyncRequest.onreadystatechange = stateChange;
    		asyncRequest.open('GET', url, true);
    		asyncRequest.send(null);
    	} 
    	catch (exception){
    		alert('Your request is failed');
    	} 
    }
    
    	function stateChange(){
    		if (asyncRequest.readyState == 4 && asyncRequest.status == 200){					  
                    document.getElementById('toolArea').innerHTML = asyncRequest.responseText;
                   } 
    } 
    </script>..............
    <body>
    <input type="radio" name="weight" onclick="getTools('secondTool.html')" />
    <input type="radio" name="weight" onclick="getTools('thirdTool.html')" />.......
    <div class = "toolArea" id = "toolArea">&nbsp;</div></body>
    This other html file (e.g. secondTool.html) contains the user defined JS function:
    Code:
    <script type="text/javascript">
     function updateContent(){
       ....
       ....
      }
    </script>
    <body>
      ....
      ....
      <input type="button" value="Update" onclick="updateContent()"></body>
    Code JavaScript:
     

  2. #2
    Non-Member Kalon's Avatar
    Join Date
    Aug 2010
    Location
    At my computer
    Posts
    2,012
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    for starters, your function stateChange() needs to be inside getTools(url) and not outisde of it.

  3. #3
    SitePoint Wizard bronze trophy
    Join Date
    Jul 2006
    Location
    Augusta, Georgia, United States
    Posts
    4,182
    Mentioned
    16 Post(s)
    Tagged
    4 Thread(s)
    stateChange() is within the scope of getTools() so that is not an issue (not a functional one at least). The issue is that your attempting to add a script dynamically using innerHTML, which won't work. A script tag will need to be created as a node manually and injected into the DOM apart from innerHTML, which will not execute script tags. That is why updateContent() is undefined, because it isn't seen. This were methods such as; JQuery.html() come handy, as it actually handles the dirty work of parsing script tags for you. Otherwise, you need to do it manually.

  4. #4
    Non-Member Kalon's Avatar
    Join Date
    Aug 2010
    Location
    At my computer
    Posts
    2,012
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    are you sure it's within scope?

    I have highlighted in red the open/close brackets of getTools().

    I still think the code for stateChange() need to be inside getTools().

    If stateChange() is outside of getTools(), then stateChange() won't see asyncRequest.

    But I'm not saying that is the only problem.

    Code:
     
    <script type="text/javascript">
      var asyncRequest;
    function getTools(url) {
      try
             {
    asyncRequest = new XMLHttpRequest();
    asyncRequest.onreadystatechange = stateChange;
    asyncRequest.open('GET', url, true);
    asyncRequest.send(null);
    } 
    catch (exception){
    alert('Your request is failed');
    } 
    }
     
    function stateChange(){
    if (asyncRequest.readyState == 4 && asyncRequest.status == 200){   
                    document.getElementById('toolArea').innerHTML = asyncRequest.responseText;
                   } 
    } 
    </script>..............

  5. #5
    Non-Member Kalon's Avatar
    Join Date
    Aug 2010
    Location
    At my computer
    Posts
    2,012
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    in this example, if you put requestHandler() outside of testAjax() then the alert() will not work and you will get a "scope" error (at least in my IE8 I do)

    index.htm

    Code:
     
    <script type="text/javascript">
        function startAJAX(){
            var xmlHttp = null;   
            try {
                // Firefox, Opera 8.0+, Safari Browsers
                xmlHttp = new XMLHttpRequest();
            }
            catch (e)
            {    
                try {
                    // IE Browsers v6+
                    xmlHttp =new ActiveXObject("Msxml2.XMLHTTP");  
                }
                catch (e) {
                    try {
                        // IE Browsers v5+
                        xmlHttp =new ActiveXObject("Microsoft.XMLHTTP");
                    }
                    catch (e) {
                        alert("Your browser does not support AJAX!");
                    }   
                }    
            } 
            return xmlHttp;     
        }
        //==========================================
     
    function testAjax() {
            var ajaxObj = startAJAX();
            if(ajaxObj == null) return;
            ajaxObj.onreadystatechange=requestHandler;
     
            var url = "formProcessor.php";
            ajaxObj.open("GET",url,true);
            ajaxObj.send(null);
     
            function requestHandler() {
                if(ajaxObj.readyState==4 && (ajaxObj.status == 200 || ajaxObj.status == 304)) {
                    alert('response = '+ajaxObj.responseText);
                }
            }
        }
    </script>
     
    <button onclick="testAjax();">test</button>
    formProcessor.php

    Code:
     
    <?php
     
    echo 'hello world';
     
    ?>

  6. #6
    SitePoint Wizard bronze trophy
    Join Date
    Jul 2006
    Location
    Augusta, Georgia, United States
    Posts
    4,182
    Mentioned
    16 Post(s)
    Tagged
    4 Thread(s)
    functions can see everything outside them unless the function is nested within another function.

    HTML Code:
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    <html>
    <head>
    	<title>Untitled</title>
    	<meta name="generator" content="BBEdit 9.6">
    	
    	<script type="text/javascript">
    	
    	
    	(function() {
    		b();
    		alert(typeof(c) === 'undefined'?'c doesn\'t exist':'c exist');
    	})();
    	
    	function b() {
    		alert('b called');
    	
    		function c() { }
    		
    	}
    	
    	</script>
    	
    </head>
    <body>
    </body>
    </html>

  7. #7
    Non-Member Kalon's Avatar
    Join Date
    Aug 2010
    Location
    At my computer
    Posts
    2,012
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Moi View Post
    I still think the code for stateChange() need to be inside getTools().

    If stateChange() is outside of getTools(), then stateChange() won't see asyncRequest.

    But I'm not saying that is the only problem.
    as per my previous example code.

  8. #8
    SitePoint Wizard bronze trophy
    Join Date
    Jul 2006
    Location
    Augusta, Georgia, United States
    Posts
    4,182
    Mentioned
    16 Post(s)
    Tagged
    4 Thread(s)
    Quote Originally Posted by Kalon
    in this example, if you put requestHandler() outside of testAjax() then the alert() will not work and you will get a "scope" error (at least in my IE8 I do)
    Yes, requestHandler() will not function as intended in that case because ajaxObj is declared within testAjax(). Therefore, requestHandler() will be called but ajaxObj will be undefined within the context of requestHandler(). Which is a significant difference to the original posters code because the asyncRequest is a global, accessible to all functions. Which is what I meant by it isn't a functional issue, though we all know the story with globals. The real issue is that the poster is trying to execute dynamic JavaScript with innerHTML, which isn't going to work. The dynamic JavaScript either needs to be evaled or added as a script node. This is where using event bubbling can come in handle to react to a click on the element added dynamically without using eval() or some other messy technique.

  9. #9
    Non-Member Kalon's Avatar
    Join Date
    Aug 2010
    Location
    At my computer
    Posts
    2,012
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    yep ok, didn't notice that the ajax object was declared globally.

    it's not something I do or would encourage anyone to do.

    I just saw the request handler being outside the calling function.

  10. #10
    SitePoint Guru
    Join Date
    Sep 2006
    Posts
    731
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Even in published AJAX examples, it's a common mistake to refer to the request object by name. It still works when the handler is nested but can cause problems.
    Just use the this reference, which will reference the request object regardless of the location of the handling function:
    Code:
    function stateChange(){
    		if (this.readyState == 4 && this.status == 200){					  
                    document.getElementById('toolArea').innerHTML = this.responseText;
                   }
    Tab-indentation is a crime against humanity.

  11. #11
    Non-Member Kalon's Avatar
    Join Date
    Aug 2010
    Location
    At my computer
    Posts
    2,012
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thanks Logic Ali

    I think "mistake" is a bit harsh because technically it is not incorrect, but I can see your suggestion is a "better" or more "flexible" way of doing it.

    but either way, my preference is to embed the request handler in the calling function, especially since it is unlikely to be used elsewhere, and thus keep everything together.

  12. #12
    SitePoint Guru
    Join Date
    Sep 2006
    Posts
    731
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Kalon View Post
    I think "mistake" is a bit harsh because technically it is not incorrect, but I can see your suggestion is a "better" or more "flexible" way of doing it.
    When the request object is global (which it doesn't need to be), it could get re-assigned while a previous request is pending, causing the handler of the pending request to address the properties of the wrong object.
    Tab-indentation is a crime against humanity.

  13. #13
    Non-Member Kalon's Avatar
    Join Date
    Aug 2010
    Location
    At my computer
    Posts
    2,012
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Logic Ali View Post
    When the request object is global (which it doesn't need to be), it could get re-assigned while a previous request is pending, causing the handler of the pending request to address the properties of the wrong object.
    yep totally agree and I posted earlier that I wouldn't encourage anyone to declare the object globally.

    please don't misunderstand me.

    when I said I thought "mistake" was a bit harsh I was referring to referring to the ajax object by its name and not the "this" keyword.

  14. #14
    SitePoint Guru
    Join Date
    Sep 2006
    Posts
    731
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Kalon View Post
    please don't misunderstand me.

    when I said I thought "mistake" was a bit harsh I was referring to referring to the ajax object by its name and not the "this" keyword.
    That's what I understood.
    Tab-indentation is a crime against humanity.

  15. #15
    SitePoint Member
    Join Date
    Oct 2010
    Posts
    6
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Hi all,

    so what's the best way of handle this? using jQuery or other javascript library?

  16. #16
    SitePoint Guru
    Join Date
    Sep 2006
    Posts
    731
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Code:
    <script type="text/javascript">
    
    function getTools(url)
    {
     var asyncRequest; /* Not global */
    
     try
       {
        asyncRequest = new XMLHttpRequest();
        asyncRequest.onreadystatechange = stateChange;
        asyncRequest.open('GET', url, true);
        asyncRequest.send(null);
       } 
       catch (exception)
       {
        alert('Your request failed');
       } 
    }
    
    function stateChange()
    {
     if ( this.readyState == 4 && this.status == 200 )
     {
       document.getElementById('toolArea').innerHTML = this.responseText;
     } 
    } 
    </script>
    Tab-indentation is a crime against humanity.

  17. #17
    SitePoint Member
    Join Date
    Oct 2010
    Posts
    6
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    So far what I had tried to do is created a separated js file, and put it in each of the html file. After the AJAX call, and the custom function will be called by the event handler.

    I would like to know how can I handle this using jQuery or other javascript libraries.

    Thanks.

  18. #18
    Unobtrusively zen silver trophybronze trophy
    paul_wilkins's Avatar
    Join Date
    Jan 2007
    Location
    Christchurch, New Zealand
    Posts
    14,729
    Mentioned
    104 Post(s)
    Tagged
    4 Thread(s)
    Quote Originally Posted by TiiMoo View Post
    So far what I had tried to do is created a separated js file, and put it in each of the html file. After the AJAX call, and the custom function will be called by the event handler.

    I would like to know how can I handle this using jQuery or other javascript libraries.
    Okay, with jQuery, using the load method.

    Code javascript:
    function getTools(url) {
        $('#toolArea').load(url);
    }
    Programming Group Advisor
    Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
    Car is to Carpet as Java is to JavaScript

  19. #19
    SitePoint Member
    Join Date
    Oct 2010
    Posts
    6
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thanks everyone for your great help!


Tags for this Thread

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
  •