How to use FORM, INPUT to create a field with dropdown list?

891 views
Skip to first unread message

Rudy

unread,
Jun 22, 2017, 6:34:54 AM6/22/17
to web2py-users
Hi there,

Due to the javascript reason, i need to create a form using FORM and INPUT helper. I wonder how I can create a form using these helpers with field displaying a dropdown list for selection (of customer from quotation form)? Below is a simplified version, currently i created autocomplete to display a list of customer names matched the input text while user is typing. Thanks in advance!

db.define_table('customer',
                Field('customer_name', requires=[IS_NOT_EMPTY()]),
                format='%(customer_name)s')
db.define_table('quotation',
                Field('customer', 'reference customer'),
                Field('project_name', requires=IS_NOT_EMPTY()),
                Field('total', 'double', default=0),
                auth.signature)

quote_row = db.quotation(id)
quotation_form = FORM(
                'Quotation id:', INPUT(_type='number', _name='id', _value=quote_row.id, _id='quotation_id', _readonly='True', requires=IS_NOT_EMPTY()),BR(),

                #'Customer Name:', INPUT(_type='number', _name='customer', _value=quote_row.customer, _id='quotation_customer', requires=IS_IN_DB(db, 'customer.id', '%(customer_name)s')),BR(),  DIV(_style="position: absolute;", _id="suggestions", _class="suggestions"), BR(),
                'Customer Name:', INPUT(_type='text', _name='customer', _value=db.customer(quote_row.customer).customer_name, _id='quotation_customer', requires=IS_IN_DB(db, 'customer.id', '%(customer_name)s')),BR(), DIV(_style="position: absolute;", _id="suggestions", _class="suggestions"), BR(),

                'Project Name:', INPUT(_type='text', _name='project_name', _value=quote_row.project_name, _id='quotation_project_name'),BR(),
                'Total:', INPUT(_type='number', _step='0.01', _name='total', _value=quote_row.total, _id='quotation_total', _readonly='True'),BR(),
                INPUT(_type='submit'))

villas

unread,
Jun 24, 2017, 9:36:58 AM6/24/17
to web2py-users
If you are building a FORM with lower-level components, you might also wish to use:

SELECT( OPTION('text1', _value='1'), OPTION('text2', _value='2')  )


Rudy

unread,
Jun 25, 2017, 2:48:51 AM6/25/17
to web2py-users

Villas,

Thanks so much, I will take this approach. I just thought i might be able to use IS_IN_DB and/or .represent to create this dropdown. Appreciate your input! Rudy

Peter

unread,
Jun 25, 2017, 10:44:19 PM6/25/17
to web...@googlegroups.com

Almost straight from the book but using my own db fields - tested and works...

This controller in default.py

def from_factory():
form = SQLFORM.factory(Field('your_name', requires = IS_IN_DB(db,db.person.id,'%(first_name)s')))
if form.process().accepted:
response.flash = 'form accepted'
session.your_name = form.vars.your_name
elif form.errors:
response.flash = 'form has errors'
return dict(form=form)

with this view 'from_factory.html'

{{extend 'layout.html'}}
{{=form}}

gives a drop down list of person's first_names.

The selected name is now held in the cookie  'session.your _name'

but if you want the table id then,

replace...        session.your_name = form.vars.your_name

with something like ...       session.person_id = form.vars.id

Hope this helps.

Peter

[edit]
Sorry I notice you are looking for something a little more complex so here is something I put together with help!
I'm not saying it is ideal or perfect but the logic worked for me...

I added a lazy field at the end of a table that calls a function to build the required dropdown view I wanted...

e.g.
db.person.display_name = Field.Virtual('display_name', get_person_display_name)


def get_person_display_name(row):
    if row.person.person_type == 'CLIENT':
        if row.person.referrer_ref:
            display_name = '%s %s' % (row.person.referrer_ref, row.person.first_name)
        else:
            display_name = 'PAP/%s %s' % (row.person.id, row.person.first_name)

    elif row.person.person_type == 'CONTACT':
        display_name = '%s, %s' % (row.person.last_name, row.person.first_name)

    return display_name


but I am beginning to understand the problem more with the dependency on INPUT helper for js
given that
"input tag has an optional attribute _type that can be set to "text" (the default), "submit", "checkbox", or "radio"."
non of which is a drop down obviously...

I did try the various _types in...
{{=INPUT(_type='text',_name='mychoice', requires = IS_IN_DB(db,db.person.id,'%(first_name)s'))}}
it doesn't complain but it doesn't do what you want either
.

Sorry if I have wasted your time!







Anthony

unread,
Jun 26, 2017, 10:00:15 AM6/26/17
to web2py-users
You do not need to use FORM() and INPUT() helpers just because you need to construct some custom markup for the form. Instead, use SQLFORM as usual and use the form.custom.widget widgets it generates to compose your form, as described here: http://web2py.com/books/default/chapter/29/07/forms-and-validators#Custom-forms. You can use those widgets either in the view within custom HTML (as shown in the book), or inside the FORM() helper if you really prefer that method.

You can also generate just the SELECT widget as follows:

SQLFORM.widgets.options.widget(db.quotation.customer, quote_row.customer)

Anthony

Rudy

unread,
Jul 11, 2017, 8:31:21 AM7/11/17
to web...@googlegroups.com
Hi Anthony,

Sorry I was on another issue, took me away for 2 weeks from below matter. Actually i have no issue using SQLFORM, SQLFORM.factory, now I tried custom widget, it works well with dropdown box for customer field. The real goal is.... I have a field "total" in the quotation, its value depends on the sum of all individual items, user should not modify it manually, but I want my javascript to update it when user changes the discount on edit_quote.html page. So i defined this "total" field with writable=False, but I couldn't retrieve the value using jQuery('#quotation_total').val(), then I used Firefox Inspector to find out what HTML element it used, then i used parseFloat(jQuery('#quotation_total__row').find(".col-sm-9").text()) to retrieve the value, then my javascript replaced the value in the form in the view, now I hit submit button, this 'total' field value doesn't get sent to the server. I did many try and error, it seems writable=True make a field disable instead of readonly. This is the whole reason why i used FORM and INPUT to construct everything from scratch (actually quite painful), so when I defined INPUT(.... _readonly='True'), i could retrieve the value using  jQuery('#quotation_total').val() and update it, submit the form also sent the total value to the callback function.

When i tried custom widget, the behavior was the same that submitting a form didn't sent the non-writable field to server, I need some SERIOUS HELP. Is there any way I can make the writable=False field readonly?

Hi Peter, thanks for taking time out to share your the SQLFORM.factory() insight, there is no waste of time at all.

Rudy

unread,
Jul 11, 2017, 1:31:29 PM7/11/17
to web2py-users
Anthony,

I just tested it again, form.widget.fieldname WORKS with _readonly. Earlier i had 'total' field defined in Field() with writable=True, somehow it didn't like it when i set this field _readonly= True. Thank you so much (also to Peter and Villas)!

(I changed the test table to invoice)
In controller:
row = db.invoice(1)
form = SQLFORM(db.invoice, row, formstyle='table2cols')
form.custom.widget.total['_readonly'] = True

In view:
{{=form.custom.begin}}
Invoice Id: <div>{{=form.custom.widget.id}}</div>
Customer: <div>{{=form.custom.widget.customer}} </div>
Project Name: <div>{{=form.custom.widget.project_name}}</div>
Total: <div>{{=form.custom.widget.total}}</div>
{{=form.custom.submit}}
{{=form.custom.end}}

<script>
jQuery(document).ready(function(){
    jQuery('#invoice_project_name').change(function(){
        var invoice_total = jQuery('#invoice_total').val();
        alert("invoice_total = " + invoice_total);
        jQuery('#invoice_total').val('4000');
    });
});
</script>
Reply all
Reply to author
Forward
0 new messages