Okay, that explains the behaviour. How, then, are values usually preserved on an ajax form for the built-in widgets? When I submit the form all of the other fields (not using my widget) preserve the newly submitted values.
def editform(self, rargs=None, rvars=None):
"""
"""
db = current.db
flash = ''
rjs = ''
duplink = ''
default_vars = {}
if rargs is not None:
tablename = rargs[0]
showid = rvars['showid'] or True
dbio = False if 'dbio' in rvars.keys() and rvars['dbio'] == 'False' else True
formstyle = rvars['formstyle'] or 'ul'
deletable = rvars['deletable'] or True
copylabel = rvars['copylabel'] or SPAN(_class='glyphicon glyphicon-file')
orderby = rvars['orderby'] or 'id'
restrictor = rvars['restrictor'] or None
collation = rvars['collation'] or None
postprocess = rvars['postprocess'] or None
if len(rargs) > 1: # editing specific item
rowid = rargs[1]
formname = '{}/{}'.format(tablename, rowid)
formargs = [db[tablename], rowid]
# create a link for adding a new row to the table
duplink = A(copylabel,
_href=URL('plugin_listandedit',
'dupAndEdit.load',
args=[tablename, rowid],
vars=rvars),
_class='plugin_listandedit_duplicate',
cid='viewpane')
elif len(rargs) == 1: # creating new item
formname = '{}/create'.format(tablename)
default_vars = {k: v for k, v in rvars.iteritems()
if hasattr(db[tablename], k)}
formargs = [db[tablename]]
form = self._myform(formargs,
deletable=deletable,
showid=showid,
formstyle=formstyle)
# print {'default_vars': default_vars}
# for k in default_vars: form.vars.setitem(k, default_vars[k])
for k in default_vars: form.vars[k] = default_vars[k]
# FIXME: ajaxselect field values have to be added manually
# FIXME: this check will fail if ajaxselect widget is for field indx[1]
if db[tablename].fields[1] in rvars.keys():
extras = [f for f in db[tablename].fields
if f not in form.vars.keys()]
for e in extras:
form.vars[e] = rvars[e] if e in rvars.keys() \
else ''
if 'id' in form.vars.keys() and form.vars['id'] in (None, ''):
del(form.vars['id'])
else:
pass
# print 'form vars in editform ---------------------------------'
# pprint(form.vars)
if form.process(formname=formname, dbio=dbio).accepted:
flash = ''
if postprocess:
flash += '{} '.format(self._post_process(form.vars, postprocess))
if dbio:
flash += 'The changes were recorded successfully.'
# either redirect or refresh the list pane
if 'redirect' in rvars and 'True' == rvars['redirect']:
redirect(URL(rvars['redirect_c'], rvars['redirect_a']))
else:
the_url = URL('plugin_listandedit', 'itemlist.load',
args=[tablename], vars={'orderby': orderby,
'restrictor': restrictor,
'collation': collation})
rjs = "window.setTimeout(web2py_component('{}', " \
"'listpane'), 500);".format(the_url)
elif form.errors:
print '\n\nlistandedit form errors:'
pprint({k: v for k, v in form.errors.iteritems()})
print '\n\nlistandedit form vars'
pprint({k: v for k, v in form.vars.iteritems()})
print '\n\nlistandedit request vars'
pprint({k: v for k, v in rvars.iteritems()})
flash = 'Sorry, there was an error processing ' \
'the form. The changes have not been recorded.'
else:
pass
else:
flash = 'Sorry, you need to specify a type of record before' \
'I can list the records.'
form = None
return form, duplink, flash, rjs
class AjaxSelect(object):
"""
"""
def __init__(self, field, value, indx=0,
refresher=None, adder=True,
restricted=None, restrictor=None,
multi=True, lister=False,
rval=None, sortable=False,
orderby=None):
# raw args
self.field = field
self.indx = indx
self.refresher = refresher
self.adder = adder
# isolate setting of param for easy overriding in subclasses
self.restricted = self.restrict(restricted)
self.restrictor = restrictor
self.multi = multi
self.lister = lister
self.rval = rval
self.sortable = sortable
self.orderby = orderby
# find table referenced by widget
self.fieldset = str(field).split('.')
self.linktable = get_linktable(field)
# processed variables
self.wrappername = self.get_wrappername(self.fieldset)
self.form_name = '%s_adder_form' % self.linktable # for referenced table form
# get the field value (choosing db or session here)
self.value = self.choose_val(value)
try:
if value and len(value) > 0:
self.clean_val = ','.join(map(str, value))
else:
self.clean_val = value
except TypeError:
self.clean_val = value
# args for add and refresh urls
self.uargs = self.fieldset
# vars for add and refresh urls
self.uvars = {'wrappername': self.wrappername,
'refresher': refresher,
'adder': self.adder,
'restrictor': self.restrictor,
'multi': self.multi,
'lister': self.lister,
'restricted': self.restricted,
'sortable': self.sortable,
'orderby': self.orderby,
'indx': self.indx}
def widget(self):
"""
Place initial load container for controller to fill.
"""
# prepare classes for widget wrapper
wclasses = self.get_classes(self.linktable, self.restricted,
self.restrictor, self.lister, self.sortable)
uvars = self.uvars
uvars.update({self.fieldset[1]: self.value})
# create SPAN to wrap widget
wrapper = SPAN(_id=self.wrappername, _class=wclasses)
wrapper.append(LOAD('plugin_ajaxselect', 'set_widget.load',
args=self.uargs, vars=uvars,
target=self.wrappername,
ajax=False))
return wrapper
def widget_contents(self):
"""
Main method to create the ajaxselect widget. Calls helper methods
and returns the wrapper element containing all associated elements
"""
#session = current.session
#request = current.request
wrapper = CAT()
# create and add content of SPAN
widget = self.create_widget()
refreshlink = self.make_refresher(self.wrappername, self.linktable,
self.uargs, self.uvars)
adder, modal = self.make_adder(self.wrappername, self.linktable)
wrapper.components.extend([widget, refreshlink, adder])
# create and add tags/links if multiple select widget
if self.multi and (self.lister == 'simple'):
taglist = self.make_taglist()
elif self.multi and (self.lister == 'editlinks'):
taglist = self.make_linklist()
else:
taglist = ''
wrapper.append(taglist)
return wrapper, modal
def create_widget(self):
"""
create either a single select widget or multiselect widget
"""
if not self.multi in [None, False, 'False']:
if self.orderby:
w = FilteredMultipleOptionsWidget.widget(self.field, self.value,
orderby=self.orderby,
multiple='multiple')
else:
w = MultipleOptionsWidget.widget(self.field, self.value)
#place selected items at end of sortable select widget
if self.sortable:
try:
for v in self.value:
opt = w.element(_value=v)
i = w.elements().index(opt)
w.append(opt)
del w[i - 1]
except AttributeError, e:
if type(v) == 'IntType':
opt = w.element(_value=self.value)
i = w.elements().index(opt)
w.append(opt)
del w[i - 1]
else:
print e
except Exception, e:
print e, type(e)
else:
if self.orderby:
w = FilteredOptionsWidget.widget(self.field, self.value,
orderby=self.orderby)
else:
w = OptionsWidget.widget(self.field, self.value)
w['_id'] = '{}_{}'.format(self.fieldset[0], self.fieldset[1])
w['_name'] = self.fieldset[1]
return w