Difference with JSLink with render() and display

11 views
Skip to first unread message

MR

unread,
Dec 5, 2006, 12:40:57 PM12/5/06
to TurboGears
Hi everyone,

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

Adam Jones

unread,
Dec 5, 2006, 1:01:28 PM12/5/06
to TurboGears

MR wrote:
> Hi everyone,
>
> 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().

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.

Alberto Valverde

unread,
Dec 5, 2006, 2:54:14 PM12/5/06
to turbo...@googlegroups.com

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

Matthew Russell

unread,
Dec 5, 2006, 4:06:41 PM12/5/06
to turbo...@googlegroups.com
Alberto -- awesome! Thanks for the tip. I'll try this later today. Seems to be just what I need. JSLink now seems a lot less mysterious :)

Also, I've looked into what Adam Jones said about not being able to execute scripts after page load by creating them on the fly and this seems to definitely be the case. I don't have a copy of Opera, but did note this thread: http://my.opera.com/community/forums/topic.dml?id=63445 what speaks to version ~7.5 or so



exclusively, so please update your address books.

Jason Chu

unread,
Dec 5, 2006, 6:08:17 PM12/5/06
to turbo...@googlegroups.com

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

signature.asc
Reply all
Reply to author
Forward
0 new messages