The select widget allows you to select one or more values from a set of given options. The “SELECT” and “OPTION” elements are described here:
http://www.w3.org/TR/1999/REC-html401-19991224/interact/forms.html#edef-SELECT
As for all widgets, the select widget must provide the new IWidget interface:
>>> from zope.interface.verify import verifyClass >>> from z3c.form import interfaces >>> from z3c.form.browser import select>>> verifyClass(interfaces.IWidget, select.SelectWidget) True
The widget can be instantiated only using the request:
>>> from z3c.form.testing import TestRequest >>> request = TestRequest()>>> widget = select.SelectWidget(request)
Before rendering the widget, one has to set the name and id of the widget:
>>> widget.id = 'widget-id'
>>> widget.name = 'widget.name'
We also need to register the template for at least the widget and request:
>>> import zope.component >>> from zope.pagetemplate.interfaces import IPageTemplate >>> from z3c.form.testing import getPath >>> from z3c.form.widget import WidgetTemplateFactory>>> zope.component.provideAdapter( ... WidgetTemplateFactory(getPath('select_input.pt'), 'text/html'), ... (None, None, None, None, interfaces.ISelectWidget), ... IPageTemplate, name=interfaces.INPUT_MODE)
If we render the widget we get an empty widget:
>>> print widget.render()
<select id="widget-id" name="widget.name:list"
class="select-widget" size="1">
</select>
<input name="widget.name-empty-marker" type="hidden"
value="1" />
Let’s provide some values for this widget. We can do this by defining a source providing ITerms. This source uses descriminators which will fit our setup.
>>> import zope.schema.interfaces >>> from zope.schema.vocabulary import SimpleVocabulary >>> import z3c.form.term>>> class SelectionTerms(z3c.form.term.Terms): ... def __init__(self, context, request, form, field, widget): ... self.terms = SimpleVocabulary.fromValues(['a', 'b', 'c'])>>> zope.component.provideAdapter(SelectionTerms, ... (None, interfaces.IFormLayer, None, None, interfaces.ISelectWidget) )
Now let’s try if we get widget values:
>>> widget.update()
>>> print widget.render()
<select id="widget-id" name="widget.name:list"
class="select-widget" size="1">
<option id="widget-id-novalue" value="--NOVALUE--">no value</option>
<option id="widget-id-0" value="a">a</option>
<option id="widget-id-1" value="b">b</option>
<option id="widget-id-2" value="c">c</option>
</select>
<input name="widget.name-empty-marker" type="hidden" value="1" />
If we select item “b”, then it should be selected:
>>> widget.value = ['b']
>>> widget.update()
>>> print widget.render()
<select id="widget-id" name="widget.name:list"
class="select-widget" size="1">
<option id="widget-id-novalue" value="--NOVALUE--">no value</option>
<option id="widget-id-0" value="a">a</option>
<option id="widget-id-1" value="b" selected="selected">b</option>
<option id="widget-id-2" value="c">c</option>
</select>
<input name="widget.name-empty-marker" type="hidden" value="1" />
Let’s now make sure that we can extract user entered data from a widget:
>>> widget.request = TestRequest(form={'widget.name': ['c']})
>>> widget.update()
>>> widget.extract()
['c']
When “no value” is selected, then no verification against the terms is done:
>>> widget.request = TestRequest(form={'widget.name': ['--NOVALUE--']})
>>> widget.update()
>>> widget.extract(default=1)
['--NOVALUE--']
Unfortunately, when nothing is selected, we do not get an empty list sent into the request, but simply no entry at all. For this we have the empty marker, so that:
>>> widget.request = TestRequest(form={'widget.name-empty-marker': '1'})
>>> widget.update()
>>> widget.extract()
[]
If nothing is found in the request, the default is returned:
>>> widget.request = TestRequest()
>>> widget.update()
>>> widget.extract(default=1)
1
Let’s now make sure that a bogus value causes extract to return the default as described by the interface:
>>> widget.request = TestRequest(form={'widget.name': ['x']})
>>> widget.update()
>>> widget.extract(default=1)
1
Additionally to the standard dynamic attribute values, the select widget also allows dynamic values for the “no value message”. Initially, we have the default message:
>>> widget.noValueMessage
u'no value'
Let’s now register an attribute value:
>>> from z3c.form.widget import StaticWidgetAttribute >>> NoValueMessage = StaticWidgetAttribute(u'- nothing -')>>> import zope.component >>> zope.component.provideAdapter(NoValueMessage, name='noValueMessage')
After updating the widget, the no value message changed to the value provided by the adapter:
>>> widget.update()
>>> widget.noValueMessage
u'- nothing -'
In certain scenarios it is desirable to ask the user to select a value and display it as the first choice, such as “please select a value”. In those cases you just have to set the prompt attribute to True:
>>> widget.prompt = True
>>> widget.update()
>>> print widget.render()
<select id="widget-id" name="widget.name:list"
class="select-widget" size="1">
<option id="widget-id-novalue" value="--NOVALUE--"
selected="selected">select a value ...</option>
<option id="widget-id-0" value="a">a</option>
<option id="widget-id-1" value="b">b</option>
<option id="widget-id-2" value="c">c</option>
</select>
<input name="widget.name-empty-marker" type="hidden"
value="1" />
As you can see, even though the field is not required, only the explicit prompt is shown. However, the prompt will also be shown if the field is required:
>>> widget.required = True
>>> widget.update()
>>> print widget.render()
<select id="widget-id" name="widget.name:list"
class="select-widget required" size="1">
<option id="widget-id-novalue" value="--NOVALUE--"
selected="selected">select a value ...</option>
<option id="widget-id-0" value="a">a</option>
<option id="widget-id-1" value="b">b</option>
<option id="widget-id-2" value="c">c</option>
</select>
<input name="widget.name-empty-marker" type="hidden"
value="1" />
Since the prompy uses the “no value” as the value for the selection, all behavior is identical to selecting “no value”. As for the no-value message, the prompt message, which is available under
>>> widget.promptMessage
u'select a value ...'
can also be changed using an attribute value adapter:
>>> PromptMessage = StaticWidgetAttribute(u'please select a value')
>>> zope.component.provideAdapter(PromptMessage, name='promptMessage')
So after updating the widget you have the custom value:
>>> widget.update()
>>> widget.promptMessage
u'please select a value'
Additionally, the select widget also allows dynamic value for the prompt attribute . Initially, value is False:
>>> widget.prompt = False
>>> widget.prompt
False
Let’s now register an attribute value:
>>> from z3c.form.widget import StaticWidgetAttribute >>> AllowPrompt = StaticWidgetAttribute(True)>>> import zope.component >>> zope.component.provideAdapter(AllowPrompt, name='prompt')
After updating the widget, the value for the prompt attribute changed to the value provided by the adapter:
>>> widget.update()
>>> widget.prompt
True
The select widget comes with a template for DISPLAY_MODE. Let’s register it first:
>>> zope.component.provideAdapter( ... WidgetTemplateFactory(getPath('select_display.pt'), 'text/html'), ... (None, None, None, None, interfaces.ISelectWidget), ... IPageTemplate, name=interfaces.DISPLAY_MODE)>>> widget.mode = interfaces.DISPLAY_MODE >>> widget.value = ['b', 'c'] >>> widget.update() >>> print widget.render() <span id="widget-id" class="select-widget required"> <span class="selected-option">b</span>, <span class="selected-option">c</span> </span>