Section 16.1. Understanding Widgets


16.1. Understanding Widgets

CherryPy, Kid, SQLObject, and MochiKit bring a lot to the table. TurboGears Widgets add another element which helps to complete the package. Other frameworks provide you mechanisms for reusing dynamic HTML snippets, and a couple even let you reuse chunks of JavaScript in your pages. But the turbogears.widgets package goes beyond all of that to make it easy to just call a widget in your template and have the HTML, CSS, and Javascript automatically added to your pagein the right places. But that's not all, widgets also help you to encode form results back into the right kind of Python objects, and handle any validation errors!

Widgets can be as simple as an HTML form element like the TextField or a MultipleSelect box, or they can be more complex Ajax-driven elements like the AutoCompleteField, Calender, Ajax Form, or the Lightbox Widgets.

As we mentioned in Chapter 5, "Enhancing Our Bookmark Application," you can safely send data into a widget in one of three ways:

  • Assign a default at instantiation time

  • Pass data in at render time

  • Assign a callable at instantiation time which will return the required valuesthe callable will be executed at render time

About the only thing you shouldn't do is try to add data to your widget object outside of instantiation or render time. This is because widget objects are shared by all incoming requests. This means that changing attributes any time other than at instantiation or render time can lead to your data being used when answering another request.

16.1.1. Instantiation Time Customizations

One of the simplest and most common use cases for building your own widget is to create a form field with some of the customization points preselected. For example, say you want a text field widget with a particular default text to appear in several different forms. You could just write:

name = TextField(default="Enter your name here!")


You can then include this name widget in several forms, or render it on the page by itself, and it will always have the default text you want.

Perhaps this is overkill for something like default text, but it is very useful for slightly more complex widgets like the SelectField widget, which requires that you pass it a list of tuples defining the value and options for the widget to display.

domain_list = [(0, "google.com"), (1, "gmail.com"), (2, "blogger.com") domain_selector = SingleSelectField(Options = domain_list, default=0)


You can also build a custom template for your widgets, and set up a new widget to always use that template:

name = TextField(default="Enter your name here!" template="bookmarker.templates. namewidget)


In this case you'd also need to create a template file namewidget.kid, which might look something like this:

<input xmlns:py="http://purl.org/kid/ns#"     type="text"     name="${name}"               value="${value}"     py:attrs="attrs"     size="30"     maxlength="30" />


This template is the same as the standard TextField widget, except that we added the size and maxlength attributes. This means that our form will show a text field 30 characters wide, and not allow users to enter any more characters after that.

Of course, this is a trivial template modification. In fact the Widgets package even provides a shortcut for this kind of thingbut we'll get back to that in a second. For now it provides us with a simple example of how you can customize the template used to render a widget. If you wanted to you could create much more complex templates, with whatever HTML, JavaScript, or CSS you might need.

All widgets have the following attributes, any of which can be assigned at instantiation time:

Table 16.1. Default Widget Attributes

Attribute

Description

name

The name of the widget.

template

Kid template for the widget.

default

Default value for the widget.

css

List of CSSLinks and CSSSources for the widget. These will be automatically pulled and inserted in the page template that displays it.

javascript

List of JSLinks and JSSources for the widget. Same as css.

is_named

A property returning True if the widget has overridden its default name.

params

All parameter names listed here will be treated as special parameters. This list is updated by the metaclass and always contains *all* params from the widget itself and all its bases.

params_doc

A dictionary that contains each of the 'params' names and its associated docstring, which will be displayed in the Widget Browser


Some widgets have other attributes that you can use to customize their look or behavior. See section 16.2.2 for a complete listing of each of the standard TurboGears widgets and the attributes available for those widgets.

16.1.2. Render Time Attribute Assignment

Most of the time, if you want to set the value of a form widget that the user will see pre-populated in the form, you want to do it at render time, when you have the data from the database that you want to appear in the widget. We saw this in Chapter 5, where we pulled the bookmark.link and other fields out of the database and assigned the defaults right at render time.

To do this, just drop the values you need into the form widget in your Kid template like this:

${my_form(value=values, action=action)


Assuming you set up a dictionary of values with keys that match the names of the widgets on your forms, this whole thing will just work, and any missing values will either be given the default you defined at instantiation time or left empty if you didn't define a default.

There's actually one exception to this, which happens when you have form validation errors, but we'll come back to that in section 16.4 of this chapter, "Widgets and Validation."

16.1.3. Using Callables with Widgets

In Chapter 5, we saw how we could create a function (or really any callable), which we pass to our widget at initialization time. That function then calculates the list of options the widget needs every time the widget is rendered.

Our function grabbed the current list of categories from the database and returned them to the widget:

def get_category_options():     categories = model.Categories.select()     options = []     for category in categories:         options.append((category.id, category.categoryName))     return options


We passed our callable into the widget in the same way we would the list of tuples it produces:

select_categories = widgets.MultipleSelectField(options=get_category_options)


This allows us to isolate the code necessary to create our options list in a function rather than repeating it in every form or controller that uses the widget. This is an incredibly useful idiom because it makes the widget capable of calculating its own options and helps keep our controllers and views clean and easy to understand.




Rapid Web Applications with TurboGears(c) Using Python to Create Ajax-Powered Sites
Rapid Web Applications with TurboGears: Using Python to Create Ajax-Powered Sites
ISBN: 0132433885
EAN: 2147483647
Year: 2006
Pages: 202

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net