I found a pretty unclean workaround... You have to set the widget like this :
db.tablename.REFERENCEDTABLEOFCHILDFIELD.widget = \ lazy_options_widget(on_key='no_table_PARENTFIELDNAME__selected', off_key='PARENTFIELDNAME__unselected', where=lambda PARENTFIELDNAME: (some where clause), trigger=record_row.get('PARENTFIELDNAME', None), orderby=db.REFERENCEDTABLEOFCHILDFIELD.id, suggest_widget=False, widget_chained=True, row=record_row, field_requires=db.tablename.REFERENCEDTABLEOFCHILDFIELD.requires # We pass the original field requires that we want to be execute in context to limit as much as possible the number of records that will be pulled out the database and only when the parent field will be updated... #user_signature=True, # If you want to process ajax requests at the time of the object construction # (not at the form rendered), specify your target field in the following: ) db.tablename.REFERENCEDTABLEOFCHILDFIELD.requires = IS_IN_SET([1, 2, 3]) # Here redefine the child field or lazy option controlled field with dummy not computer intensive requires that will be never displayed NOTE: I have a customized version of lazy_option_widget (NOT THIS ONE : https://github.com/scubism/sqlabs/blob/master/modules/plugin_lazy_options_widget.py) that support reference field... So it might not make more sens without the code so here it is... # -*- coding: utf-8 -*- # This plugins is licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php # Authors: Kenji Hosoda <hos...@s-cubism.jp> # Support for reference field : Richard Vézina from gluon import * class lazy_options_widget(SQLFORM.widgets.options): def __init__(self, on_key, off_key, where, trigger=None, # Rename this attribute suggest_widget=True, # In case you don't want to use plugin_suggest_widget, set suggest_widget to # False. In this case, this piece of js with be including : # $("select[name=<CONDITIONAL_FIELD_NAME>]").change(function() { # var val = $(this).children(":selected").attr("value"); # $(this).trigger($(this).attr("id") + "__selected", [val]); # }); # Where <CONDITIONAL_FIELD_NAME> will be replaced with the field name of the # conditional field name. widget_chained=False, # In case the widget field is also a conditional field for another widget field # you need to trigger event like "WIDGET_FIELD_NAME__selected" when the widget # field option is finally selected widget_trigger_event_js=None, # If you need to trigger something when the widget field option is # finally selected you can pass a piece of js here that will be injected # into the form when the conditional field trigger event "__selected" default='---', keyword='_lazy_options_%(fieldname)s', orderby=None, user_signature=False, hmac_key=None, row=None, # In order to set values and filtered drop down appropriately based on values of # conditional and widget field when the form is populated. Since you can't get row like this # Field(..., widget=lambda field, value, row: ... # When form is populated (update form) you need to define a row object base on the id of # the record like this : # row = db(db.table.id = request.vars.id ).select(db.table.ALL).first() # and pass it to lazy_option_widget... field_requires=None, # Better to set the field requires here to get it evaluated in a lazy manner ): self.on_key, self.off_key, self.where = ( on_key, off_key, where ) self.field_requires = field_requires self.trigger, self.default, self.keyword, self.orderby = ( trigger, default, keyword, orderby, ) self.user_signature, self.hmac_key = user_signature, hmac_key self.row = row self.suggest_widget, self.widget_trigger_event_js, self.widget_chained = (suggest_widget, widget_trigger_event_js, widget_chained) if self.suggest_widget == True: self.suggest_widget = 'true' else: self.suggest_widget = 'false' # if field: # self.process_now(field) def _get_select_el(self, trigger, value=None): trigger_event_selected = SCRIPT('''$(function() { $("#%(aux_tag_id)s").change(function() { var val = $(this).children(":selected").attr("value"); $("#%(tag_id)s").trigger("%(tag_id)s__selected", [val]); }); });''' % {'aux_tag_id': self._el_id + '__aux', 'tag_id': self._el_id}) widget_trigger_event_js = SCRIPT(self.widget_trigger_event_js) if trigger: self._require.orderby = self.orderby or self._require.orderby self._require.dbset = self._require.dbset(self.where(trigger)) options = self._require.options() opts = [OPTION(v, _value=k) for (k, v) in options] # multiple = {} # if self._require.multiple is True: # multiple['_multiple'] = 'multiple' return DIV(SELECT(_id='%s__aux' % self._el_id, value=value, _onchange='jQuery("#%s").val(jQuery(this).val());' % self._hidden_el_id, *opts, **self.multiple), trigger_event_selected if self.widget_chained is True else '', widget_trigger_event_js if self.widget_trigger_event_js is not None else '') else: return self.default def _pre_process(self, field): self._keyword = self.keyword % dict(fieldname=field.name) self._el_id = '%s_%s' % (field._tablename, field.name) self._disp_el_id = '%s__display' % self._el_id self._hidden_el_id = '%s__hidden' % self._el_id requires = field.requires if self.field_requires: requires = self.field_requires if isinstance(requires, IS_EMPTY_OR): requires = requires.other if not isinstance(requires, (list, tuple)): requires = [requires] if requires: if hasattr(requires[0], 'options'): self._require = requires[0] else: raise SyntaxError('widget cannot determine options of %s' % field) else: self._require = [] self.multiple = {} if self._require.multiple is True: self.multiple['_multiple'] = 'multiple' def process_now(self, field): if not hasattr(self, '_keyword'): self._pre_process(field) 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) trigger = current.request.vars[self._keyword] raise HTTP(200, self._get_select_el(trigger)) return self def __call__(self, field, value, **attributes): self._pre_process(field) request = current.request if hasattr(request, 'application'): self.url = URL(r=request, args=request.args, user_signature=self.user_signature, hmac_key=self.hmac_key) self.process_now(field) else: self.url = request script_el = SCRIPT(""" jQuery(document).ready(function() { jQuery("body").on("%(on_key)s", function(e, val) { jQuery("#%(disp_el_id)s").html("%(default)s"); //jQuery("#%(hidden_el_id)s").val(""); jQuery("#%(hidden_el_id)s option:selected").prop("selected", false); var query = {} query["%(keyword)s"] = val; jQuery.ajax({type: "POST", url: "%(url)s", data: query, success: function(html) { jQuery("#%(disp_el_id)s").html(html); }}); }); jQuery("body").on("%(off_key)s", function(e) { jQuery("#%(disp_el_id)s").html("%(default)s"); //jQuery("#%(hidden_el_id)s").val(""); jQuery("#%(hidden_el_id)s option:selected").prop("selected", false); }); var suggest_widget = '%(suggest_widget)s' if (suggest_widget == 'false') { $("select#%(conditional_field_name)s").change(function() { var val = $(this).children(":selected").attr("value"); $(this).trigger($(this).attr("id") + "__selected", [val]); }); } });""" % dict(on_key=self.on_key, off_key=self.off_key, disp_el_id=self._disp_el_id, hidden_el_id=self._hidden_el_id, default=self.default, keyword=self._keyword, url=self.url, suggest_widget=self.suggest_widget, conditional_field_name=self.on_key[0:-10] )) if value and self.row and current.request.vars.keyword is None: el = DIV(script_el, SPAN(self._get_select_el(trigger=self.row[self.off_key[0:-12]], value=value), _id=self._disp_el_id), SELECT(*[OPTION(v, _value=k) for (k, v) in self.field_requires], value=value, _name=field.name, _id=self._hidden_el_id, _style='display: none;', **self.multiple), _id=self._el_id) else: # select_el = self._get_select_el(self.trigger, value) if self.trigger else None select_el = None # This is just a test might prevent update form to display selected value properly el = DIV(script_el, SPAN(select_el or self.default, _id=self._disp_el_id), SELECT(*[OPTION(v, _value=k) for (k, v) in field.requires.options()], value=value, _name=field.name, _id=self._hidden_el_id, _style='display: none;', **self.multiple), _id=self._el_id) return el On Thu, Mar 15, 2018 at 5:47 PM, Richard Vézina <ml.richard.vez...@gmail.com > wrote: > I wonder if we could we also make field lazy that way in context of custom > form... > > I find some issue with some of my custom form where I use Field() to > define my field that will be use... This form is also dynamic, I manipulate > field visibility and lazy_option_widget() to make some field depend of > other field... The things is with data build up... > requires=IS_EMPTY_OR(IS_IN_DB(_set_, 'table.id', ...)), is loading at > first (on form load) all the records almost everything as I can't specify > the id which will be selected in the parent field the one controlling the > lazy_option controlled field (hope I am understandable)... Multiply this by > 3-4 time for each lazy_option controlled field and you ends up pulling > multiple time the same records... > > I would be interred in making the IS_IN_DB() triggered select occuring > only when options needed to be displayed... I guess this is a flaw in the > way lazy_option_widget() is implemented in the first place though... > > Richard > > On Sun, Mar 26, 2017 at 6:34 AM, Joe Barnhart <joe.barnh...@gmail.com> > wrote: > >> That's kinda clever. I may think of that! >> >> -- Joe >> >> >> On Thursday, March 23, 2017 at 4:19:05 PM UTC-7, Anthony wrote: >>> >>> Note, you might as well also add 'type': 'string' to your dictionary, >>> and maybe 'length': 20. You can also give yourself some flexibility by >>> creating a function: >>> >>> def phone_field(name, **kwargs): >>> defaults = {'type': 'string', >>> 'length': 20, >>> 'requires': IS_EMPTY_OR(IS_PHONE()), >>> 'widget': lambda fld,val: SQLFORM.widgets.string.widget( >>> fld, val, _type='tel', _class='form-control')} >>> defaults.update(**kwargs) >>> return Field(name, **defaults) >>> >>> Anthony >>> >>> >>>> -- >> Resources: >> - http://web2py.com >> - http://web2py.com/book (Documentation) >> - http://github.com/web2py/web2py (Source code) >> - https://code.google.com/p/web2py/issues/list (Report Issues) >> --- >> You received this message because you are subscribed to the Google Groups >> "web2py-users" group. >> To unsubscribe from this group and stop receiving emails from it, send an >> email to web2py+unsubscr...@googlegroups.com. >> For more options, visit https://groups.google.com/d/optout. >> > > -- Resources: - http://web2py.com - http://web2py.com/book (Documentation) - http://github.com/web2py/web2py (Source code) - https://code.google.com/p/web2py/issues/list (Report Issues) --- You received this message because you are subscribed to the Google Groups "web2py-users" group. To unsubscribe from this group and stop receiving emails from it, send an email to web2py+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.