This has nothing todo with TG/Pylons/TW. It's solely about your model,
which you gave a constructor that's requiring a Pic-object being
constructed without always passing arguments - thus preventing a
Pic-object from being instantiated *if it already exists* and is only
supposed to be filled with DB-data.
Remove that constructor, and see how things work out.
Diez
Obviously, I meant "with" here instead of "without".
Diez
This is not correct. The method to do such stuff is "update_params", precisely
because of the statelessness of widgets - the constructor is only called once
per process (or at least supposed to, and things might break otherwise), and
as the injection has to take place on each request, you need to use
update_params.
Diez
Well, I'm not sure, but you seem to take a rather strange approach of
working with TG (or TW, in this case). It appears as if you formed an
idea of how things should work by some snippets of documentation, and
then start building wildly on them.
Take the above: you somehow are aware that there is a possibility to
declare JS-dependencies, and that there is injection. And you mix that
together to something that is looking awful, and not working ...
This is not meant to be offensive - it's just something I've noted. And
so far, I haven't seen anybody else doing this. But then, I've certainly
not seen all newbie code.
So for the above:
- the classlevel-attribute "js" is not known to TW. It's called
"javascript"
- the template is not defined inside update_params.
- update_params is not a general replacement for the constructor -
it's just for the *dynamic* parts of a widget, and to prepare stuff for
the template namespace.
- templates are given without their extension.
So with what I can grasp from the above, I'd say what you want looks
like this:
class PicForm(TableForm):
engine_name = "genshi" # sometimes this is needed for me, maybe you
can get aloning without it
template = "pkg.templates.pic" # no need for html here, causes the
error you see
javascript = [JSLink(link=url('/public/js/chart.js'))]
class fields(WidgetsList):
id = TextField()
title = TextField()
fig = TextArea()
And yes, I think that's rather beautiful compared to PL/SQL mixed with HTML.
> Maybe not, as I see there was some fairly extensive discussion on tg-
> trunk
> re. this update_params stuff.
>
> Now I get another ImportError. Is it because I haven't injected
> because
> no params are allowed in update_params? If so, where/how can I put
> the call
> to inject_resources?
You usually don't do that. TW does that for you, **if** you declare them
properly.
Resource injection is only needed if you want something inside the page
that isn't a dependency of some other wiget that gets called it's
display()-method.
>
> ======================================================
> Module ?:27 in <Expression u'tmpl_context.pic_form()'> view
> << pic_form with template = "pkg.templates.pic.html"
> This seems to want a 'pic' module. I have one in /
> model -->
> <p>${tmpl_context.pic_form()}</p>
> <!-- :-( ImportError on module pic ...?! -->
You have a pic-subpackage by declaring a template
"pkg.templates.pic.html" because the html is superflous, and assumed to
be actually a file called "html.html" inside a module called pic.
HTH,
Diez
The constructor is still odd. Whoever created that example didn't use tw
idiomatic. And it in general seems to be a rather bad example, see below.
Use
class TestWidget(JUnit):
javascript = [test_js]
instead, if you must use JUnit.
> def update_params(self, d):
> super(TestWidget, self).upadate_params(d)
Superflous, can go.
>
> #templates/widgettest.html
> #...
> ${tmpl_context.testwidget(value=value)}
> ===========================================
> ! UndefinedError: "value" not defined
> Where am I supposed to get this value from?
The value is supposed to be passed via returnvalue from the controller.
I don't know what it is supposed to be for the JSUnit-widget, because
the whole page doesn't care to mention this.
So, do yourself a favor, and ditch that whole thing. It is official
docs, so it's sad that you stumbled over it. But it unfortunatly sucks.
Instead, try this:
class MyWidet(tw.api.Widget):
javascript = [JSLink(__modname__, "myscript.js")] # make sure that
the js is really under __modname__/myscript.js
template = "<div>Hello world!</div>"
engine_name = "genshi"
my_widget = MyWidget("test")
@expose("the.template")
def action(self, ...):
c.my_widget = my_widget
return dict
And in "the.template.html", do
${c.my_widget.display()}
This should work, render a jslink into the source, and the "hello
world". From there on, try to expand, by e.g. using add_call inside
"update_params" to render a piece of js that invokes code from myscript.js.
Diez
Don't do this, use the modname/filename variant. The reason is that
tg.url can't work on module-import-time, as it needs access to the
environment to really work, and that's only available in a request.
And even if tg.url would work, overall it's not working because
"/js/chart.js" is a relative path to something the system doesn't
recognize - unless you have a js-named controller on your root, and a
chart_js-action on that. Which you don't have I presume.
BTW, in my example I used the modname/filenam-variant. Why did you
change it? And did it work for you?
> template = "pkg.templates.widgettest"
> engine_name = "genshi"
>
> def __init__(self, name):
> super(TestWidget, self).__init__(self)
>
> def update_params(self, d):
> super(TestWidget, self).upadate_params(d)
> #I read that this must be done explicitly
> self.add_call(javascript)
> #Invoke javascript from myscript.js here?
> #But won't this re-inject the JS for
> #every rendering? I thought I read TG's
> #smart enough to do it just once if I ...?
Again this seems to be some exercise in genetic programming. Yes, TW
*is* smart enough to inject the resoure.
It is also smart enough to insert the add_call, but that's supposed to
contain a string that will be rendered like a JSSource-widget, and it
should contain some widget-specific code, such as
self.add_jall("""$(document).ready(function() {
$("#%s").do_something();
})""" % d.id)
And where does the "javascript" come from?
> testwidget = TestWidget("TestTW")
>
>
> @expose('pkg.templates.widgettest')
> def widgettest(self, **kw):
> pylons.c.widgettest = testwidget
> return dict(form=testwidget) #, action=blah, value=blah)
Both the widget and the controller share the same template? How's that
supposed to work? Either you are not rendering a full HTML-page, then
the resource injection of course can't work (it needs
html/head/body-tags), or you rendering those *twice*
>
> <body>
> <p py:content="form.display(submit_text='Yes')">
> Widget Form</p>
> gave me UndefinedError: "tg" not defined
>
>
> The above code works in the sense that there
> are no errors thrown. Clicking on the link
> for my controller method 'widgettest' renders
> the page with title and the text in the div
> that is supposed to be replaced. But no JS
> action occurs onscreen. :{
As you don't show us the template, I can't comment on that.
>
> PS.
> There is nothing in the rendered page's
> source <head> section resulting.
>
> Putting the code below into the template works
> in so far as it appears if I View Page Source.
> However, nothing happens, the JS does not
> appear to run.
> <script type="text/javascript" src="${tg.url('/js/chart.js')}"></
> script>
IT does not do something for the reasons explained above - /js/chart.js
isn't delivered by the system.
Diez