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.

Reply via email to