10

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(incomingTicket){
    
        //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.net/vm4bG/4/

However, when I combine 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 complete 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.org:81/rfc1.htm

<html>
<head>
<script type="text/javascript" src="http://public.tableausoftware.com/javascripts/api/viz_v1.js"></script>
<script type="text/javascript" src="http://code.jquery.com/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.org: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.com%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.org: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(incomingTicket){

// grab tableau template code and replace ticket placeholder with incomingTicket 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(incomingTicket);
    console.log("Appended.");

}

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


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


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

4

2 に答える 2

5

FYI, your tableau.russellchristopher.org 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 );
于 2012-05-31T13:13:42.970 に答える
4

提示された膨大な量のコードから、実際に遭遇しているものを正確に判断するのは難しいため、一般的な原則は次のとおりです。

DOM要素を見つけて操作するには、その要素が存在している必要があります。したがって、たとえば、このコードは失敗します。

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

実例| ソース

ターゲットは更新されません。このコードは機能します:

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

実例| ソース

唯一の違いは、scriptタグがターゲットの後にあることです。そのため、ターゲットを操作しようとしている時点で、ターゲットがDOMに存在していることがわかります。(これは信頼できます。Googleの開発チームがそれについて何と言っているか、およびYUIガイドラインを参照してください。)

ライブラリには従来、「DOM対応」イベントが含まれています。これは、組み込みのloadイベントであるオブジェクトのイベントが、プロセスの非常に遅い段階(すべての画像を含むすべての外部参照が読み込まれると)windowまで発生しないためです。しかし、画像がまだ読み込まれているときでも、人々はもっと早く物事をやりたいと思っていました。「ready」スタイルのイベントを使用すると、スクリプトコードをマークアップのどこにでも配置できます(何らかの理由で、スクリプトコードを配置するのが好きです)が、「ready」イベントを使用する場合は、すべてが実行されるまで実際には呼び出されないことがわかります。マークアップが処理されました。head

つまり、結果は次のようになります。readyイベントを使用するか、(より適切に)要素に依存するコードをマークアップ内のそれらの要素の</body>(通常は終了タグの直前に最適)に移動します。

于 2012-05-25T16:57:52.183 に答える