I spent an awful lot of time last night learning that if I instantiate
a widget and call it's render method that the javascript files
referenced with "javascript = JSLink(...)" are apparently not made
available in the serialized output (or any other way I could find) to
be loaded into the document's head (or anywhere else for that
matter)...But obviously the javascript is automatically loaded into the
head for you when you call a widget's display() method from the kid
template.
What I was trying to do was use render() to get a widget's HTML so that
I could shove it into a div at some point after a page had been loaded.
The HTML arrived just fine, but the JavaScript did not. This was
totally counter-intutive to me, so could someone please comment on why
render() doesn't include the JavaScript in a <script> tag as part of
the serialized output? I really am just trying to find a way to get a
widget's JavaScript so that it can be loaded into a page *without*
using display().
Is there an approved way to get at the actual javascript with an
existing mechanism, or is my assumption that it's a "good idea" to try
and do this for purposes of loading JavaScript into the head after page
load actually a bad idea?
An example (not tested, but serves the example)
def FooWidget(Widget):
template = "..."
javascript = [JSLink(...)]
def someMethodInController():
foo = FooWidget()
html = foo.render()
#how to get javascript out of FooWidget with instantiation of
FooWidget?
#I want to create a script element and shove it into a page after
page load
I would guess this happens because newly included scripts are
automatically executed and would step over any state variables they
contain. You should be able to programmatically get at a widget's
JSLink/JSSource with the widgets retrieve_javascript() method. From
there it gets a little more tricky, at least for JSLinks.
You should be able to build the address for a JSLink with the following
string interpolation:
"/%stg_widgets/%s/%s" % (turbogears.startup.webpath, <widget>.mod,
<widget>.name)
Returning the source of a JSSource is easy, it is stored as
<widget>.src
>
> Is there an approved way to get at the actual javascript with an
> existing mechanism, or is my assumption that it's a "good idea" to try
> and do this for purposes of loading JavaScript into the head after page
> load actually a bad idea?
>From what I have seen this isn't supported on Opera < 8.0. Might not be
supported on other platforms as well. I didn't spend much time looking
into it.
You could fetch the resources by calling the widget's retrieve_css and
retrieve_javascript methods and then rendering them manually.
js = widget.retrieve_javascript()
css = widget.retrieve_css()
all_rendered_js = ''.join(j.render() for j in js)
all_rendered_css = ''.join(c.render() for c in css)
widget_plus_its_resources = ''.join([all_rendered_js, all_rendered_css,
widget.render()]
This is (more or less) what turbogears.view.templates.sitetemplate does
with resources collected from all widgets you return in the output dict or
list at tg.include_widgets in app.cfg.
HTH,
Alberto
exclusively, so please update your address books.
I thought I wrote about this in a blog post, but I didn't get to
exactly the issue...
It's not the .display() that adds javascript to the headers of a page,
it's returning the widget in your controller. The expose decorator
sees that you passed a widget to the template and adds the JSLink to
the header. If you don't call .display() for a widget or even
reference it in the template, but still return it in the dict, the
JSLink references will show up.
Remember that when you call .render() all the widget does is spit out a
string that is the template rendered. Turbogears has no idea where
that text came from, that it was a widget, or that that widget had
JSLink javascript with it... Even if Turbogears did know all of that,
you'd still have the problem you already heard about with loading
script tags after the page is loaded.
Now you know,
Jason