← Back to the web2py-plugin list
Suggest Widget
The suggest widget is an alternative for a built-in autocomplete widget. It uses suggest.js with some modifications to handle non-us charcters. Further, it visualize a selecting status at each typing step.
Demo
| categories | : |
| ||||||||||||
| form | : |
Usage
-
controllers/plugin_suggest_widget.py
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.from plugin_suggest_widget import suggest_widget
db = DAL('sqlite:memory:')
db.define_table('category', Field('name'))
db.define_table('product',
Field('category_1'),
Field('category_2', db.category),
)
db.category.bulk_insert([{'name':'AAA'}, {'name':'AAC'}, {'name':'ABC'},
{'name':'BBB'}, {'name':'CCC'}])
from gluon.storage import Storage
session.auth = Storage(hmac_key='test')
################################ The core ######################################
# Inject the suggest widget
db.product.category_1.widget = suggest_widget(db.category.name, limitby=(0, 10), min_length=1)
# Inject the another suggest widget
# In this case, you have to specify the keyword argument to avoid conflict.
# You can also pass the id_field argument as in web2py's autocomplete widget.
# You can also pass user_signature and hmac_key arguments for authorization in ajax
db.product.category_2.widget = suggest_widget(
db.category.name,
id_field=db.category.id, limitby=(0, 10), min_length=1,
user_signature=True,
keyword='_autocomplete_category_2_%(fieldname)s',
)
################################################################################
def index():
form = SQLFORM(db.product)
if form.accepts(request.vars, session):
session.flash = 'submitted %s' % form.vars
redirect(URL('index'))
return dict(form=form, categories=SQLTABLE(db().select(db.category.ALL)))
Source code
-
modules/plugin_suggest_widget.py
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.from gluon import *
from gluon.sqlhtml import AutocompleteWidget
# For referencing static and views from other application
import os
APP = os.path.basename(os.path.dirname(os.path.dirname(__file__)))
class suggest_widget(AutocompleteWidget):
def __init__(self, field, id_field=None, db=None,
orderby=None, limitby=(0, 10),
keyword='_autocomplete_%(fieldname)s',
min_length=2,
user_signature=False, hmac_key=None):
self.keyword = keyword % dict(fieldname=field.name)
self.db = db or field._db
self.orderby, self.limitby, self.min_length = orderby, limitby, min_length
self.user_signature, self.hmac_key = user_signature, hmac_key
self.fields = [field]
if id_field:
self.is_reference = True
self.fields.append(id_field)
else:
self.is_reference = False
request = current.request
if hasattr(request, 'application'):
self.url = URL(r=request, args=request.args,
user_signature=user_signature, hmac_key=hmac_key)
self.callback()
else:
self.url = request
def _create_item(self, field, row):
return B(row[field.name])
def callback(self):
if self.keyword in current.request.vars:
if self.user_signature:
if not URL.verify(current.request, user_signature=self.user_signature, hmac_key=self.hmac_key):
raise HTTP(400)
field = self.fields[0]
rows = self.db(field.like(current.request.vars[self.keyword] + '%')
).select(orderby=self.orderby, limitby=self.limitby, *self.fields)
if rows:
if self.is_reference:
id_field = self.fields[1]
raise HTTP(200, UL(*[LI(self._create_item(field, row), SPAN(row[id_field.name]))
for row in rows]).xml())
else:
raise HTTP(200, UL(*[LI(self._create_item(field, row)) for row in rows]).xml())
else:
raise HTTP(200, '')
def __call__(self, field, value, **attributes):
for _url in (URL(APP, 'static', 'plugin_suggest_widget/suggest.css'),
URL(APP, 'static', 'plugin_suggest_widget/suggest.js')):
if _url not in current.response.files:
current.response.files.append(_url)
default = dict(
_type='text',
value=(value != None and str(value)) or '',
)
attr = SQLFORM.widgets.string._attributes(field, default, **attributes)
div_id = '%s__div' % self.keyword
attr['_autocomplete'] = 'off'
if self.is_reference:
key2 = '%s__aux' % self.keyword
key3 = '%s__auto' % self.keyword
attr['_class'] = 'text_32'
if 'requires' in attr:
del attr['requires']
attr['_name'] = key2
value = attr['value']
record = self.db(self.fields[1] == value).select(self.fields[0]).first()
attr['value'] = record and record[self.fields[0].name]
attr['_onfocus'] = ("""
jQuery('#%(id)s').suggest(
'%(url)s',{name:'%(name)s', keyword:'%(keyword)s',
resultsId:'%(div_id)s', minchars:'%(min_length)s'})""" %
dict(id=attr['_id'], url=self.url, name=field.name, div_id=div_id,
keyword=self.keyword, min_length=self.min_length))
return TAG[''](INPUT(**attr), INPUT(_type='hidden', _id=key3, _value=value,
_name=field.name, requires=field.requires),
DIV(_id=div_id, _style='position:absolute;'))
else:
attr['_name'] = field.name
attr['_onfocus'] = ("""
jQuery('#%(id)s').suggest(
'%(url)s',{keyword:'%(keyword)s',
resultsId:'%(div_id)s', minchars:'%(min_length)s'})""" %
dict(id=attr['_id'], url=self.url, div_id=div_id,
keyword=self.keyword, min_length=self.min_length))
return TAG[''](INPUT(**attr), DIV(_id=div_id, _style='position:absolute;'))
