Warning: Can't synchronize with repository "(default)" (Unsupported version control system "svn": No module named svn). Look in the Trac log for more information.

Ticket #1275 (closed defect: invalid)

Opened 12 years ago

Last modified 9 years ago

Kid error with three level widget injection

Reported by: quadword Owned by: jorge.vargas
Priority: high Milestone: 1.0.x bugfix
Component: unassigned Version: 1.0.1
Severity: normal Keywords:
Cc:

Description

I have a simple kid template page which insert a widget class with the following template:

class MyWidget(Widget):
   template=r"""
                <div id="accordion_widget" class="accordion_widget main" style="position:absolute;" py:attrs="attrs" xmlns:py="http://purl.org/kid/ns#">
                        <div py:if="titles" py:for="title in titles.keys()">
                            <a href="#"  class="toggler accordion_widget">${titles[title]}</a>
                                <div id="accordion_widget#1" class="accordion accordion_widget" >
                                    <div py:if="widgetdict.has_key(title) and widgetdict[title]" py:replace="widgetdict[title].display()"/>
                                </div>                            
                        </div>
                </div>
    """
   params=["field_id", "attrs", "titles", "widgetdict"]
    css = [CSSLink("css", "accordion.css"), CSSLink("js", "minikit/minikit.widget.css")]
    javascript = [mochikit, 
                    JSLink("js", "minikit/minikit.core.js"),
                    JSLink("js", "minikit/minikit.fx.js"),
                    JSSource(r"""
                                widget_start = function() {
                                    makeAccordion(getElementsBySelector("a.toggler"), getElementsBySelector("div.accordion"), {hash: true});
                                }                                
                                addLoadEvent(widget_start);
                    """)]
                    
    titles = ["Title One", "Title Two", "Title Three"]
    widgetsdict = dict()
    attrs = dict()
    
    def __init__(self, *args, **kw):
        super(Accordion, self).__init__(self, *args, **kw)

    def update_params(self, d):
        super(Accordion, self).update_params(d)


where widgetdict[title].display() is another widget as follow:

class widgetS1(Widget):
    """ Widget S1
    """
    template=r"""
                <div xmlns:py="http://purl.org/kid/ns#">
                <div  py:replace="w1.display()">
                </div>
                <div  py:replace="w2">
                </div>
                </div>
    """
    full_class_name = "myapp.mypeople_widgetS1"
    params=["field_id", "attrs", "w1", "w2"]
    attrs = dict()
    w1 = widgets.CalendarDatePicker("date_picker", attrs=dict(style="position: absolute; left: 70%;"))
    w2 = widgets.AutoCompleteField(name="state", search_controller="%s/update" % full_class_name, search_param="statename", result_name="states")
    
    def __init__(self, *args, **kw):
        super(mypeople_widgetS1, self).__init__(self, *args, **kw)

    def update_params(self, d):
        super(mypeople_widgetS1, self).update_params(d)
    
    @expose("json")
    def update():
        return dict(states=list(), result_name="states")
        pass

When it runs Kid throws an exception: AttributeError?: display, which refers to the

<div  py:replace="w1.display()">
}}} line.

If i use {{{
<div  py:replace="w1">

the widget shows well, but a Javascript error follow to say AutoCompleteField and Calendar objects are undefined. In this case the <link> tag for that object are not into generated html.

Maybe a kid or TurboGears bug ?

Attachments

TestZone.tar.bz2 Download (86.9 KB) - added by quadword 12 years ago.

Change History

comment:1 follow-up: ↓ 2 Changed 12 years ago by jorge.vargas

did you took this to the mailing list first? I think your better off with the WidgetList class then the "widgetdict" dictionary object.

Changed 12 years ago by quadword

comment:2 in reply to: ↑ 1 ; follow-up: ↓ 3 Changed 12 years ago by quadword

Replying to jorge.vargas:

did you took this to the mailing list first? I think your better off with the WidgetList class then the "widgetdict" dictionary object.

Thanks for your reply.

The problem seems depending on the display() method with stack of inner widget injection (i.e w1(w2(w3))))and, in my opinion, may depends on a del self.display in meta.py module in lockwidget() method.

I have create a tg project (see attached) with all widget classes in controllers.py module. As you can see the if replace $\{w2.display()\} with $\{w2\} the controller run well, but the css and javascript vars aren't injected into page (not present in the example code but tested by me with standard widgets like Calendar and AutoCompleteField)

comment:3 in reply to: ↑ 2 ; follow-up: ↓ 4 Changed 12 years ago by jorge.vargas

Replying to quadword:

Replying to jorge.vargas:

did you took this to the mailing list first? I think your better off with the WidgetList class then the "widgetdict" dictionary object.

Thanks for your reply.

The problem seems depending on the display() method with stack of inner widget injection (i.e w1(w2(w3))))and, in my opinion, may depends on a del self.display in meta.py module in lockwidget() method.

umm well the reason for that is to make widgets readonly ones you go into the view.

I have create a tg project (see attached) with all widget classes in controllers.py module. As you can see the if replace $\{w2.display()\} with $\{w2\} the controller run well, but the css and javascript vars aren't injected into page (not present in the example code but tested by me with standard widgets like Calendar and AutoCompleteField)

that's great feedback I think now someone can take a look at this more closely.

comment:4 in reply to: ↑ 3 Changed 12 years ago by quadword

Replying to jorge.vargas:

Replying to quadword:

Replying to jorge.vargas:

did you took this to the mailing list first? I think your better off with the WidgetList class then the "widgetdict" dictionary object.

Thanks for your reply.

The problem seems depending on the display() method with stack of inner widget injection (i.e w1(w2(w3))))and, in my opinion, may depends on a del self.display in meta.py module in lockwidget() method.

umm well the reason for that is to make widgets readonly ones you go into the view.

I have create a tg project (see attached) with all widget classes in controllers.py module. As you can see the if replace $\{w2.display()\} with $\{w2\} the controller run well, but the css and javascript vars aren't injected into page (not present in the example code but tested by me with standard widgets like Calendar and AutoCompleteField)

that's great feedback I think now someone can take a look at this more closely.

Thanks for your reply. I found in groups something about this. The problem seems to be that exposed methods can handle well only widgets into returned dict() (i say at root of the widgets tree). Also work well if a Widget contains (i think as the first level of the widgets tree) a WidgetsList? or a is a CompoundWidget?. I think this maybe considered like a framework limitation. Could be very useful using recursive widget injection into code, because in this way Widgets can be used like chinese boxes with conceptually infinite use. In example I'm trying to build an Accordion Widget. With the actual implementation of the framework I'm constrained to use more than one class to obtain the same result (perhaps with a loss of flexibility) I'll obtain using recursive injection.

Bye, qw

comment:5 Changed 12 years ago by Chris Arndt

  • Milestone set to __unclassified__

comment:6 Changed 11 years ago by chrisz

  • Status changed from new to closed
  • Resolution set to invalid

I don't think this is a bug. The real problem is that you set the params w1 and w2 like this:

    w1 = widgets.CalendarDatePicker("date_picker", attrs=dict(style="position: absolute; left: 70%;"))
    w2 = widgets.AutoCompleteField(name="state", search_controller="%s/update" % full_class_name, search_param="statename", result_name="states")

Remember that widget instances are callable, and callable parameters are automatically called by TG. So you end up with w1 and w2 being the rendered widgets already. This is the reason why you can't run the display() method on them any more, and why including them directly works. What you probably want to do is setting w1 and w2 like that:

    def w1(self):
        return widgets.CalendarDatePicker("date_picker", attrs=dict(style="position: absolute; left: 70%;"))
    def w2(self):
        return widgets.AutoCompleteField(name="state", search_controller="%s/update" % full_class_name, search_param="statename", result_name="states")

Alternatively, you can also use update_params() to set w1 and w2. This way, I got your test case working normally.

comment:7 Changed 9 years ago by chrisz

  • Milestone changed from __unclassified__ to 1.0.x bugfix
Note: See TracTickets for help on using tickets.