In the sample I've put together, I need to:
- Use a jquery POST inside $(document).ready to grab a "ticket" I use later
- On success of the post, call another function ("AddTicketAndRender()") and pass in that ticket
- 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.
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/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:
- Use a jquery POST inside $(document).ready to grab a "ticket" I use later
- On success of the post, call another function ("AddTicketAndRender()") and pass in that ticket
- 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.
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/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
2 Answers
Reset to default 5 +50FYI, 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.
One obvious problem is that your script element that contains the template is in the nether region between
</head>
and<body>
. Put it insidebody
.Here's what I think might be happening: it looks like the Tableau JavaScript API is setup to process the
object.tableauViz
elements whenDOMContentLoaded
orload
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. retrievingobject.tableauViz
elements from the document) does not appear to be accessible. It looks like you might be able to add your element by callingwindow.tableau.createViz()
, but unfortunatelycreateVizesAndStartLoading()
does some pre-processing (e.g. settingwidth
/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).