Skip to main content
https://secure.travis-ci.org/collective/collective.z3cform.chosen.png

Credits

Companies

makinacom

Authors

Contributors

Description

This package contains 4 widgets for z3cform using the chosen and ajaxchosen libraries.

  • A single valued widget for chosen

  • A multi valued widget for chosen

  • A single valued widget for ajaxchosen

  • A multi valued widget for ajaxchosen

Repository : github

Chosen widget

collective.chosen.widget provides an autocomplete widget based on the jQuery Autocomplete widget.

>>> from collective.z3cform.chosen import AjaxChosenFieldWidget
>>> from collective.z3cform.chosen import AjaxChosenMultiFieldWidget
>>> from collective.z3cform.chosen import ChosenFieldWidget
>>> from collective.z3cform.chosen import ChosenMultiFieldWidget

First, we need a vocabulary to search. This is shamelessly stolen from z3c.formwidget.query, which we extend.

>>> from zope.interface import implements
>>> from z3c.formwidget.query.interfaces import IQuerySource
>>> from zope.schema.vocabulary import SimpleVocabulary, SimpleTerm
>>> class ItalianCities(object):
...     implements(IQuerySource)
...
...     vocabulary = SimpleVocabulary((
...         SimpleTerm(u'bologna',  'bologna', u'Bologna'),
...         SimpleTerm(u'palermo',  'palermo', u'Palermo'),
...         SimpleTerm(u'sorrento', 'sorrento', u'Sorrento'),
...         SimpleTerm(u'torino', 'torino', u'Torino')))
...
...     def __init__(self, context):
...         self.context = context
...
...     __contains__ = vocabulary.__contains__
...     __iter__ = vocabulary.__iter__
...     getTerm = vocabulary.getTerm
...     getTermByToken = vocabulary.getTermByToken
...
...     def search(self, query_string):
...         return [v
...                 for v in self
...          if query_string.lower() in v.value.lower()]
>>> from zope.schema.interfaces import IContextSourceBinder
>>> class ItalianCitiesSourceBinder(object):
...     implements(IContextSourceBinder)
...
...     def __call__(self, context):
...         return ItalianCities(context)

Then, we will set up a simple test form and context.

>>> from zope.interface import alsoProvides
>>> from OFS.SimpleItem import SimpleItem
>>> from Testing.makerequest import makerequest
>>> from zope.annotation.interfaces import IAttributeAnnotatable
>>> from z3c.form.interfaces import IFormLayer
>>> def make_request(path, form={}):
...     app = SimpleItem('')
...     request = makerequest(app).REQUEST
...     request.form.update(form)
...     alsoProvides(request, IFormLayer)
...     alsoProvides(request, IAttributeAnnotatable)
...     request._script = path.split('/')
...     request._steps = []
...     request._resetURLS()
...     return request
>>> from zope.interface import Interface
>>> from zope import schema
>>> from z3c.form import form, field, button
>>> from plone.z3cform.layout import wrap_form
>>> class ICities(Interface):
...     afavourite_city = schema.Choice(title=u"Favourite city",
...                                    source=ItalianCitiesSourceBinder(), required=False)
...     avisited_cities = schema.List(title=u"Visited cities",
...                                  value_type=schema.Choice(title=u"Selection",
...                                                           source=ItalianCitiesSourceBinder()))
...     favourite_city = schema.Choice(title=u"Favourite city",
...                                    source=ItalianCitiesSourceBinder())
...     visited_cities = schema.List(title=u"Visited cities",
...                                  value_type=schema.Choice(title=u"Selection",
...                                                           source=ItalianCitiesSourceBinder()))
>>> from z3c.form.interfaces import IFieldsForm
>>> from zope.interface import implements
>>> class CitiesForm(form.Form):
...     implements(ICities)
...     fields = field.Fields(ICities)
...     fields['afavourite_city'].widgetFactory = AjaxChosenFieldWidget
...     fields['avisited_cities'].widgetFactory = AjaxChosenMultiFieldWidget
...     fields['favourite_city'].widgetFactory = ChosenFieldWidget
...     fields['visited_cities'].widgetFactory = ChosenMultiFieldWidget
...
...     @button.buttonAndHandler(u'Apply')
...     def handleApply(self, action):
...         data, errors = self.extractData()
...         print "Submitted data:", data
>>> form_view = wrap_form(CitiesForm)
>>> from zope.component import provideAdapter
>>> from zope.publisher.interfaces.browser import IBrowserRequest
>>> from zope.interface import Interface
>>> provideAdapter(adapts=(ICities, IBrowserRequest),
...                provides=Interface,
...                factory=form_view,
...                name=u"cities-form")
>>> from OFS.SimpleItem import SimpleItem
>>> class Bar(SimpleItem):
...     implements(ICities)
...
...     def __init__(self, id):
...         self.id = id
...         self.favourite_city = None
...         self.visited_cities = []
...         self.afavourite_city = None
...         self.avisited_cities = []
...     def absolute_url(self):
...         return 'http://foo/bar'

Let us now look up the form and attempt to render the widget.

>>> from zope.component import getMultiAdapter
>>> context = Bar('bar')

Simulates traversal:

>>> request = make_request('bar/@@cities-form')
>>> from Testing.makerequest import makerequest
>>> context = makerequest(context)
>>> form_view = getMultiAdapter((context, request), name=u"cities-form")
>>> form_view.__name__ = 'cities-form'

Simulates partial rendering:

>>> form = form_view.form_instance
>>> form.__name__ = 'cities-form'
>>> form.update()
>>> print form.widgets['favourite_city'].render().replace("...", "") # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE +REPORT_UDIFF
<BLANKLINE>
<script type="text/javascript">    (function($) {
        $().ready(function() {
            $('#form-widgets-favourite_city-select').data('klass','chosen-selection-widget required choice-field').data('title','None');
            $('#form-widgets-favourite_city-select').chosen({
                allow_single_deselect: false,
                no_results_text: 'No results found',
                width: '280px'
            });
<BLANKLINE>
            $('#formfield-form-widgets-favourite_city').find('.chzn-container, .chzn-results, .chzn-drop').css({'min-width': '180px'});
        });
    })(jQuery);
    </script>
<div id="form-widgets-favourite_city-chosen" class="chosen-selection-widget required choice-field">
  <select data-placeholder="Select a value" id="form-widgets-favourite_city-select" name="form.widgets.favourite_city:list" onselect="" style="" >
<BLANKLINE>
      <option id="form-widgets-favourite_city-novalue" value="(nothing)" selected="selected">Select a value</option>
<BLANKLINE>
<BLANKLINE>
<BLANKLINE>
      <option id="form-widgets-favourite_city-0" value="bologna">Bologna</option>
<BLANKLINE>
<BLANKLINE>
      <option id="form-widgets-favourite_city-1" value="palermo">Palermo</option>
<BLANKLINE>
<BLANKLINE>
      <option id="form-widgets-favourite_city-2" value="sorrento">Sorrento</option>
<BLANKLINE>
<BLANKLINE>
      <option id="form-widgets-favourite_city-3" value="torino">Torino</option>
<BLANKLINE>
  </select>
  <input name="form.widgets.favourite_city-empty-marker" type="hidden" value="1" />
</div>
<BLANKLINE>

We can see that the rendered JavaScript is expecting to call a view for ajax widgets like this:

>>> widget = form.widgets['afavourite_city']
>>> context.REQUEST._script = 'bar/@@cities-form/++widget++form.widgets.avisited_cities/@@chosen-autocomplete-search'.split('/')
>>> context.REQUEST._resetURLS()
>>> context.REQUEST.form['term'] = 'or'
>>> search_view = getMultiAdapter((widget, context.REQUEST), name=u'chosen-autocomplete-search')

The results are a json tuple list of tokens:

>>> print search_view()
[["sorrento","Sorrento"],["torino","Torino"]]

At first we didnt set anything in the request, we are missing fields

>>> form.update()
>>> data, errors = form.extractData()
>>> len(errors)
3
>>> form.request.form.update({
...  "form.buttons.apply" : "Apply",
...  "form.widgets.visited_cities" : ["palermo", "bologna"],
...  "form.widgets.avisited_cities" : ["palermo", "bologna"],
...  "form.widgets.afavourite_city" :"bologna",
...  "form.widgets.favourite_city" : "palermo",
... })
>>> form.update() # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS
Submitted data:...
>>> data, errors = form.extractData()
>>> items = data.items()
>>> items.sort(key=lambda x:x[0])
>>> pprint(items)
[('afavourite_city', u'bologna'),
 ('avisited_cities', [u'palermo', u'bologna']),
 ('favourite_city', u'palermo'),
 ('visited_cities', [u'palermo', u'bologna'])]

Our values are marked as selected

>>> results = form.render().replace('...', '')
>>> False not in [
... (it in results)
... for it in ['id="form-widgets-visited_cities-0" value="bologna" selected="selected">Bologna',
...            'id="form-widgets-visited_cities-1" value="palermo" selected="selected">Palermo']]
True

Our widget also handle display mode

>>> form.widgets['favourite_city'].mode = 'display'
>>> print form.widgets['favourite_city'].render().strip()
 <span id="form-widgets-favourite_city" class="chosen-selection-widget required choice-field" style=""><span class="selected-option">Palermo</span></span>
>>> form.widgets['visited_cities'].mode = 'display'
>>> print form.widgets['visited_cities'].render().strip()
<span id="form-widgets-visited_cities" class="chosen-multiselection-widget required list-field" style=""><span class="selected-option">Palermo</span>, <span class="selected-option">Bologna</span></span>

Our widget also handle hidden mode

>>> form.widgets['favourite_city'].mode = 'hidden'
>>> print form.widgets['favourite_city'].render().strip()
<input id="form-widgets-favourite_city-1" name="form.widgets.favourite_city:list" value="palermo" class="hidden-widget" type="hidden" />
<BLANKLINE>
<BLANKLINE>
<BLANKLINE>
<BLANKLINE>
<BLANKLINE>
<BLANKLINE>
<BLANKLINE>
<input name="form.widgets.favourite_city-empty-marker" type="hidden" value="1" />
>>> form.widgets['visited_cities'].mode = 'hidden'
>>> print form.widgets['visited_cities'].render().strip()
<input id="form-widgets-visited_cities-0" name="form.widgets.visited_cities:list" value="bologna" class="hidden-widget" type="hidden" />
<BLANKLINE>
<BLANKLINE>
  <input id="form-widgets-visited_cities-1" name="form.widgets.visited_cities:list" value="palermo" class="hidden-widget" type="hidden" />
<BLANKLINE>
<BLANKLINE>
<BLANKLINE>
<BLANKLINE>
<BLANKLINE>
<BLANKLINE>
<BLANKLINE>
<input name="form.widgets.visited_cities-empty-marker" type="hidden" value="1" />

collective.z3cform.chosen Installation

To install collective.z3cform.chosen, follow this documentation.

Changelog

1.2.2 (2021-04-20)

  • Do not translate the no value token to avoid an error when translated. [mpeeters]

  • Added needed ajax parameter for corresponding collective.js.chosen [cedricmessiant, sgeulette]

1.2.1 (2014-09-25)

  • Widget works when the field is initially hidden (for instance in an overlay). [thomasdesvenain]

  • Pyflakes, pep8, unused code removed, etc. [thomasdesvenain]

1.2 (2014-06-03)

  • Set width, and apply as chosen parameter rather than styling widgets with a specific width; doing so ensures chosen will set a valid width when it’s initialized off-screen or when the element applied to it is invisible. [damilgra]

  • Updated french translations. [cedricmessiant]

1.1 (2013-06-04)

  • buildout, tests & travis [kiorky]

  • Change prompt message and update French translations. Fix bug for no value in List fields. [cedricmessiant]

1.0 (2012-06-06)

  • Initial release [kiorky]

Release files for collective.z3cform.chosen 1.2.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for collective.z3cform.chosen 1.2.2
File Size Uploaded
collective.z3cform.chosen-1.2.2.tar.gz 35.7 kB Details

Release files / collective.z3cform.chosen-1.2.2.tar.gz

Download URL collective.z3cform.chosen-1.2.2.tar.gz
Size 35.7 kB
Tags Source
SHA-256 checksum
How to use checksums
b898d8c39afd12caec985a7146bcb76749b75d5573f246d33f2b03ed1bbab629
BLAKE2b-256 checksum
How to use checksums
1eebb2facd299595c05aaceeaa4803d1e75b9da3111c8ed0e1f2227d7d6350eb
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/1.11.0 pkginfo/1.4.2 requests/2.18.4 setuptools/39.2.0 requests-toolbelt/0.8.0 tqdm/4.23.4 CPython/2.7.11

Release history Release notifications | RSS feed

This release

1.2.2 This release

1 release file

1.2.1

1 release file

1.2

1 release file

1.1

1 release file

1.0

1 release file

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page