============= Select Widget ============= 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() 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() If we select item "b", then it should be selected: >>> widget.value = ['b'] >>> widget.update() >>> print widget.render() 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 Custom No Value Messages ------------------------ 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 -' Explicit Selection Prompt ------------------------- 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() 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() 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 Display Widget -------------- 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() # doctest: +NORMALIZE_WHITESPACE b, c Hidden Widget ------------- The select widget comes with a template for ``HIDDEN_MODE``. Let's register it first: >>> zope.component.provideAdapter( ... WidgetTemplateFactory(getPath('select_hidden.pt'), 'text/html'), ... (None, None, None, None, interfaces.ISelectWidget), ... IPageTemplate, name=interfaces.HIDDEN_MODE) We can now set our widget's mode to hidden and render it: >>> widget.mode = interfaces.HIDDEN_MODE >>> widget.value = ['b'] >>> widget.update() >>> print widget.render() # doctest: +NORMALIZE_WHITESPACE