views:

132

answers:

5

I am building a jQuery dialog with tabs in a PHP script. The script uses the 'include' directive inside of a loop, iterating over the tabs and including the other scripts. Each of the included files has the data for the tab and a <script> tag with a jQuery document.ready() function in it. Without the loop, it essentially does this:

<div id="tabDialog">
  <div id="tabs">
    <ul>
      <li><a href="#tab1'>Tab1</a></li>
      <li><a href="#tab2'>Tab2</a></li>
    </ul>
    <div id="tabContainer">
      <div id="tab1">
        <?php include "tab1.php"; ?>
      </div>
      <div id="tab2">
        <?php include "tab2.php"; ?>
      </div>
    </div>
  </div>
</div>

and, for example, tab1.php might have something like:

<script type="text/javascript">
   $(document).ready (function () {
       alert ('tab1 loaded');
   });
</script>

The problem is, upon creating and opening the dialog using the <div id="dialog"> as the dialog's DIV, the document's ready function is called a second time. Here is the dialog code:

 $("#tabDialog").dialog ({
   autoOpen: false,
   minWidth: 450,
   minHeight: 400,
   width: 600,
   height: 500
 }).dialog ('open');

What is the cause of this and what would be the best way to remedy the situation? I'm trying to keep each tab's functionality in separate files because they can be used in multiple situations and I don't have to replicate the code associated to them.

Thanks for any help or advice.

A: 

You probably don't need the .dialog('open') call; use the option autoOpen : true instead.

pixeline
Right, however each ready() function is still called twice :(.
Dave
technically, you can have several document.ready() calls in the same page. What matters is the call to your dialog() function. See also my comment to your question. Can you show us the full html code of a page that shows the error?
pixeline
I'll try to see where I can put it, or try to create a smaller example of it. I "think" the root cause of the problem is the included PHP file's <script> tag is inside of the div, which itself is inside of the dialog function. If I view the page, copy the resulting source, and move the script OUT of the DIV, it is only called once. There's something about the jQuery dialog that causes the ready() function to be called a second time.
Dave
I put the code in an answer since it was too large to put in a comment.
Dave
+1  A: 

I haven't used .dialog() too much, but do you need to use jQuery's ready() method in your script?

Looks like .dialog() has callback options you could take advantage of.

Script in tab:

    <script type="text/javascript">
        function onOpen() { alert('tab1 loaded') };
    </script>

dialog:

$(this).dialog ({
    autoOpen: false,
    minWidth: 450,
    minHeight: 400,
    width: 600,
    height: 500,
    open: function(event, ui) { onOpen(); } // call function in script
}).dialog ('open');
RightSaidFred
A: 

So I have to say that I am not 100% sure why it is happening even though I understand that the dialog does maintin it's own state so this might be one of the reasons. But I could be way off. But the way to get around it is to use something like this instead:

$(document).one('ready', function () {
   alert ('tab1 loaded');
});

This will make sure that it only runs once when the page loads.

spinon
I tried this and it still is executed twice :(.
Dave
<div id="tabDialog"> <div id="tabs"> <div id="tabContainer"> <div id="tab1"><script> $(document).one('ready', function () { alert('tab1 loaded'); });</script> </div> <div id="tab2"><script> $(document).one('ready', function () { alert('tab2 loaded'); });</script> </div> </div> </div></div><a href="javascript:Launch();">Test</a><script> function Launch() { $("#tabDialog").dialog({ autoOpen: false, }).dialog('open'); }</script>This worked for me. Trimmed code to fit comment.
spinon
Forgot to mention that I was running this against jquery version 1.3.2
spinon
Interesting. When I put that into my code, it calls each of your document.ready() functions twice. Ripping my hair out now :P.
Dave
You forgot to change the bottom document.ready to document.one. I just ran the code right now with that change and it only ran once. It is interesting that it runs it twice though.
spinon
I was searching another thread. Does the jQuery dialog "clone" the div that is being used as the dialog? Clone as in completely COPY the contents of the DIV? If so, then I think that is the problem because the SCRIPT gets copied too then, and, hence, would be in the DOM twice :(.
Dave
Yeah I was going to look into that more later. Was interested in seeing if the last change I suggested did in fact work for you though?
spinon
A: 

Here's the resulting text of the page. I did a view-source and then removed any extraneous stuff from the page to try and make it simpler.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"&gt;
<html>
    <head>
        <link href="css/redmond/jquery-ui-1.8.1.custom.css" type="text/css" rel="stylesheet" media="screen" />
        <link href="css/style.css" type="text/css" rel="stylesheet" media="screen" />
        <script src="js/jquery-1.4.2.min.js" type="text/javascript"></script>
        <script src="js/jquery-ui-1.8.1.custom.min.js" type="text/javascript"></script>
    </head>

    <body>
        <div id="tabDialog" style="position: relative; display: none;" title="Test Dialog">
            <div id="tabs" style="position: absolute; top: 5px; bottom: 40px; left: 3px; right: 3px;">
                <ul>
                    <li><a href='#tab1'>Tab #1</a></li><li><a href='#tab2'>Tab #2</a></li>
                </ul>

                <div class="tab_container" style="position: absolute; top: 35px; bottom: 0px; left: 1px; right: 1px; overflow: auto;">
                    <div id='tab1' class='tabPage ui-dialog-content'>
                        <form id="tab1Form">
                            More testing... <input class="keypressMonitor" type="text">
                        </form>
                        Testing...<br/>
                        Testing...<br/>

                        <script type="text/javascript">
                            $(document).ready (function () {
                                alert ('tab1 loaded');
                                $("#tab1Form").bind ('save', function () {
                                    alert ("in tab1Form.save ()");
                                });
                            });
                        </script>
                    </div>

                    <div id='tab2' class='tabPage ui-dialog-content'>
                        <form id="tab2Form">
                            <div style="position: absolute; left: 1px; right: 1px; top: 1px; bottom: 1px;">
                                Testing: <input class="keypressMonitor" type="text">

                                <textarea id="testArea" class="keypressMonitor tinymce" style="position: absolute; top: 30px; bottom: 2px; left: 2px; right: 2px;"></textarea>
                            </div>
                        </form>

                        <script type="text/javascript">
                            $(document).ready (function () {
                                $("#tab2Form").bind ('save', function () {
                                    alert ("in tab2Form.save ()");
                                });
                            });
                        </script>
                    </div>
                </div>
            </div>

            <div id="dialogButtons" style="position: absolute; bottom: 3px; left: 3px; right: 15px; text-align: right; height: 32px;">
                <button class="applyButton" disabled>Apply</button>
                <button class="okButton" disabled>Ok</button>
                <button class="cancelButton">Cancel</button>
            </div>
        </div>

        <script type="text/javascript">
            $(document).ready (function () {
                $("#tabs").tabs ();
                $("button").button ();

                /**
                 * Pressing the cancel button simply closes the dialog.
                 */
                $(".cancelButton").click (function () {
                    $("#tabDialog").dialog ("close");
                });

                $("#tabDialog").dialog ({
                    open: function () {
                    },
                    autoOpen: true,
                    minWidth: 450,
                    minHeight: 400,
                    width: 600,
                    height: 500,
                    height: 'auto'
                });
            });
        </script>
    </body>
</html> 
Dave
A: 

I believe I've found the reason and created a reasonably good fix. When jQuery creates the dialog, it moves the DIV that contains the contents of the dialog around in the DOM (to the very end of the document) and surrounds that div with the necessary scaffolding that a dialog requires (probably by using the .append() function or something similar). Because the DIV which was being dynamically had Javascript contained within it, jQuery was calling the document.ready() function after the DIV was relocated in the DOM (i.e. a second time). Therefore, prior to building the dialog, I .remove() every script tag within the dialog's DIV like this:

    $("#tabDialog").find ("script").remove ();
    $("#tabDialog").dialog ({
      autoOpen: true,
      minWidth: 450,
      minHeight: 400,
      width: 600,
      height: 500
    });

Doing this removes the SCRIPT tag from the DIV which it was originally loaded in, but the SCRIPT itself still exists. I'm still researching this because I don't completely understand where the Javascript code that was dynamically loaded actually "lives," but I suspect it's located somewhere outside of the DOM. I verified this in Chrome, Firefox, and Exploder 8.

I verified that any scripts that were originally contained within the loaded DIVs still function as expected by putting a button in the DIV and assigning a .click() function. Here is a small test that demonstrates this:

<html>
  <head>
    <link href="css/redmond/jquery-ui-1.8.1.custom.css" type="text/css" rel="stylesheet" media="screen" />
    <link href="css/style.css" type="text/css" rel="stylesheet" media="screen" />

    <script src="js/jquery-1.4.2.js" type="text/javascript"></script>
    <script src="js/jquery-ui-1.8.1.custom.min.js" type="text/javascript"></script>
  </head>

  <body>
    <div id="dialogContents" style="display: none;">
      <div  style="border: 1px solid black; height: 98%;">
        <form id="testForm">
          <input type="text">
        </form>
        <button id="testButton">Test</button>
        <script type="text/javascript">
          $(document).ready (function () {
            alert ("ready");

            $("#testButton").click (function () {
              alert ('click');
            });
          });
        </script>
      </div>
    </div>
  </body>

  <script type="text/javascript">
    $(document).ready (function () {
      //
      // Remove all the scripts from any place in the dialog contents.  If we
      // do not remove the SCRIPT tags, the .ready functions are called a
      // second time.  Removing this next line of Javascript demonstrates this.
      //
      $("#dialogContents").find ("script").remove ();
      $("#dialogContents").dialog ({
        width: 300,
        height: 300,
        title: 'Testing...'
      });
    });
  </script>

</html>

I appreciate the help people provided in this thread!

Dave