admin管理员组

文章数量:1336585

In the sample I've put together, I need to:

  1. Use a jquery POST inside $(document).ready to grab a "ticket" I use later
  2. On success of the post, call another function ("AddTicketAndRender()") and pass in that ticket
  3. In AddTicketAndRender(), replace a placeholder value in an HTML template with the ticket that was passed in. The HTML template defines an object I need to render.
  4. Add the HTML template to body and render:

    function addTicketAndRender(iningTicket){
    
        //For now, just touch the spinner, don't worry about the ticket.
        var template = $('#tableauTemplate').html(),
            filledTemplate = template.replace('{placeholder}','yes');
    
    
        $('body').append( filledTemplate );}
    

I have this working in jsfiddle:

/

However, when I bine the HTML and JavaScript together into a single htm file, the visualization I want isn't getting rendered in Chrome, IE, or Firefox.

Here is plete source from the HTM that isn't working. Can anyone see something that is obviously wrong? My markup & script is below and/or here: :81/rfc1.htm

<html>
<head>
<script type="text/javascript" src=".js"></script>
<script type="text/javascript" src=".7.2.min.js"></script>
</head>

<!-- template code follows -->
<script type="text/template" id="tableauTemplate">

<div class="tableauPlaceholder" id="tableauPlaceholder" style="width:654px; height:1469px;background-image: url(':81/Background.gif'); top: 0px; left: 0px; width: 100%; margin-left: 76px;">
    <object class="tableauViz" width="654" height="1469">
        <param name="host_url" value="http%3A%2F%2Fpublic.tableausoftware%2F"/>
        <param name="site_root" value="" />
        <param name="name" value="AnalyticsIncJavaScript&#47;AnalyticsInc" />
        <param name="tabs" value="no" />
        <param name="toolbar" value="yes" />
        <param name="static_image" value="tableau.russellchristopher:81/Background.gif"/>
        <param name="animate_transition" value="yes" />
        <param name="display_static_image" value="yes" />
        <param name="display_spinner" value="{placeholder}" id="display_spinner" />
        <param name="display_overlay" value="yes" />
        <param name="display_count" value="yes" />
    </object>
</div>
</script>
<!-- end of template -->

<body>
<script>
function addTicketAndRender(iningTicket){

// grab tableau template code and replace ticket placeholder with iningTicket from $.post
console.log("Add and Render");

    //For now, just touch the spinner, don't worry about the ticket.
    var template = $('#tableauTemplate').html(),
        filledTemplate = template.replace('{placeholder}','no');


    $('body').append( filledTemplate );
    console.log(iningTicket);
    console.log("Appended.");

}

$(document).ready(function() {
    console.log("ready");
    var trustedURL = "",
        userName = "foo",
        serverURL = "/";


    $.post(trustedURL, {
       username: userName,
        server: serverURL,
        client_ip: "",
        target_site: ""
    }, function(response) {
        addTicketAndRender(response);
    });


});

</script>


</body>

</html>      

Calls to console.log in the success function are logging correct information - so I know I'm getting where I need to - but the object doesn't seem to be doing what it needs to.

In the sample I've put together, I need to:

  1. Use a jquery POST inside $(document).ready to grab a "ticket" I use later
  2. On success of the post, call another function ("AddTicketAndRender()") and pass in that ticket
  3. In AddTicketAndRender(), replace a placeholder value in an HTML template with the ticket that was passed in. The HTML template defines an object I need to render.
  4. Add the HTML template to body and render:

    function addTicketAndRender(iningTicket){
    
        //For now, just touch the spinner, don't worry about the ticket.
        var template = $('#tableauTemplate').html(),
            filledTemplate = template.replace('{placeholder}','yes');
    
    
        $('body').append( filledTemplate );}
    

I have this working in jsfiddle:

http://jsfiddle/vm4bG/4/

However, when I bine the HTML and JavaScript together into a single htm file, the visualization I want isn't getting rendered in Chrome, IE, or Firefox.

Here is plete source from the HTM that isn't working. Can anyone see something that is obviously wrong? My markup & script is below and/or here: http://tableau.russellchristopher:81/rfc1.htm

<html>
<head>
<script type="text/javascript" src="http://public.tableausoftware./javascripts/api/viz_v1.js"></script>
<script type="text/javascript" src="http://code.jquery./jquery-1.7.2.min.js"></script>
</head>

<!-- template code follows -->
<script type="text/template" id="tableauTemplate">

<div class="tableauPlaceholder" id="tableauPlaceholder" style="width:654px; height:1469px;background-image: url('http://tableau.russellchristopher:81/Background.gif'); top: 0px; left: 0px; width: 100%; margin-left: 76px;">
    <object class="tableauViz" width="654" height="1469">
        <param name="host_url" value="http%3A%2F%2Fpublic.tableausoftware.%2F"/>
        <param name="site_root" value="" />
        <param name="name" value="AnalyticsIncJavaScript&#47;AnalyticsInc" />
        <param name="tabs" value="no" />
        <param name="toolbar" value="yes" />
        <param name="static_image" value="tableau.russellchristopher:81/Background.gif"/>
        <param name="animate_transition" value="yes" />
        <param name="display_static_image" value="yes" />
        <param name="display_spinner" value="{placeholder}" id="display_spinner" />
        <param name="display_overlay" value="yes" />
        <param name="display_count" value="yes" />
    </object>
</div>
</script>
<!-- end of template -->

<body>
<script>
function addTicketAndRender(iningTicket){

// grab tableau template code and replace ticket placeholder with iningTicket from $.post
console.log("Add and Render");

    //For now, just touch the spinner, don't worry about the ticket.
    var template = $('#tableauTemplate').html(),
        filledTemplate = template.replace('{placeholder}','no');


    $('body').append( filledTemplate );
    console.log(iningTicket);
    console.log("Appended.");

}

$(document).ready(function() {
    console.log("ready");
    var trustedURL = "http://tableau.russellchristopher/trusted",
        userName = "foo",
        serverURL = "http://tableau.russellchristopher/";


    $.post(trustedURL, {
       username: userName,
        server: serverURL,
        client_ip: "",
        target_site: ""
    }, function(response) {
        addTicketAndRender(response);
    });


});

</script>


</body>

</html>      

Calls to console.log in the success function are logging correct information - so I know I'm getting where I need to - but the object doesn't seem to be doing what it needs to.

Share Improve this question edited May 29, 2012 at 14:25 Russell Christopher asked May 25, 2012 at 16:48 Russell ChristopherRussell Christopher 1,7073 gold badges21 silver badges36 bronze badges 4
  • 2 The Element doesn't get appended, because the DOM is not ready. That's why there is a "DOM ready" event. – Johannes Klauß Commented May 25, 2012 at 16:51
  • Beware jsFiddle. By default, it puts your JavaScript code in the onload event, which happens very, very late in the page load process (long after "DOM ready"). And indeed your jsfiddle/vm4bG/2 fiddle is set up exactly that way (and includes MooTools; did you want MooTools?). – T.J. Crowder Commented May 25, 2012 at 16:53
  • But if I'm calling the function which does this work from inside $(document).ready(), wouldn't, by definition the DOM be ready? – Russell Christopher Commented May 25, 2012 at 17:36
  • One problem might be that you are attempting to append an element with the same id as an existing element. Element IDs must be unique... – mgnoonan Commented May 30, 2012 at 16:45
Add a ment  | 

2 Answers 2

Reset to default 5 +50

FYI, your tableau.russellchristopher link doesn't work. I don't know how you would have this working in jsfiddle either -- I get a cross origin error when I try it.

  1. One obvious problem is that your script element that contains the template is in the nether region between </head> and <body>. Put it inside body.

  2. Here's what I think might be happening: it looks like the Tableau JavaScript API is setup to process the object.tableauViz elements when DOMContentLoaded or load fires. You're inserting the <object> markup into the document in the callback for an async request. So I'm thinking that the load events are firing, and the Tableau API is doing it's initialization before your <object> markup is inserted into the document.

    Perhaps register your own listeners for those events and call console.log() to see if they execute before your $.post callback.

    Unfortunately, the createVizesAndStartLoading() method that performs the initialization (e.g. retrieving object.tableauViz elements from the document) does not appear to be accessible. It looks like you might be able to add your element by calling window.tableau.createViz(), but unfortunately createVizesAndStartLoading() does some pre-processing (e.g. setting width / height values) that you'd either need to duplicate or forego.

Retrieve template synchronously

Try this instead of your $.post():

$.ajax( {

  url : trustedURL,

  data : {

    username : userName,

    server : serverURL,

    client_ip : "",

    target_site : ""

  },

  async : false

} ).done( addTicketAndRender );

It's hard to tell from the vast amount of code presented exactly what you're running into, so the general principle:

In order to find and operate on a DOM element, the element must exist. So for instance, this code will fail:

<script>$("#target").html("Updated");</script>
<p id="target">Not updated</p>

Live example | source

The target won't get updated. This code will work:

<p id="target">Not updated</p>
<script>$("#target").html("Updated");</script>

Live example | source

The only difference is that the script tag is after the target, so you know the target exists in the DOM as of when you're trying to operate on it. (This is reliable; see what Google's dev team have to say about it, and the YUI guidelines.)

Libraries traditionally include "DOM ready" events because the built-in one, the load event of the window object, doesn't fire until very, very late in the process (once all external references have been loaded, including all images). But people wanted to do things earlier, even when images were still loading. The "ready" style events allow script code can be placed anywhere in the markup (people like putting it in head, for some reason), but if it uses the "ready" event, it knows that it won't actually get called until all the markup has been processed.

So the upshot is: Either use the ready event, or (better) move your code that relies on elements to after those elements in the markup (usually best right before the closing </body> tag).

本文标签: javascriptltobjectgt created by function called from (document)ready not renderedStack Overflow