How to solve vertical alignment too high of SQLForm read-only field

199 views
Skip to first unread message

Martin de Groot

unread,
Nov 21, 2016, 10:42:54 AM11/21/16
to web2py-users
In a SQLForm all widget-controls of writable fields are nicely, correctly vertically aligned with the preceding label.

However, when one adds db.table.field.writable = False in the contrller-action function the widget-control is correctly changed from an input control to a read-only control, but the text of the field's value is placed noticeably higher than the text of the preceding label.

I have been looking into the html source code of the resulting page, to see if I could figure out which style I could apply in an extra .css file statement, but I cannot  find anything.

I am sure many other users have observed this vertical alignment being too high , especially if the text in the field is just on one line.

I would very much appreciate it if anyone can suggest a solution for this. Apart from making a custom form, which is a lot more work than using the SQLForm generated code.

Martin de Groot

Sundar

unread,
Nov 29, 2016, 8:52:07 AM11/29/16
to web2py-users
Yes- it looks very bad. I think the below method will work. (Let me know if you need any elaboration)

rofields = [db.<table>.field1, .....]
hidden = {}
for f in rofields:
fname = str(f).split('.')[1]
hidden[fname] = r[fname]
form1 = SQLFORM(db.<table>, record=<recid> , showid=True, hidden=hidden)
for f in rofields:
fname = str(f).split('.')[1]
try: 
form1.element('input', _name=fname)['_disabled'] = 'true'
except:
pass
try:
form1.element('textarea', _name=fname)['_disabled'] = 'true'
except:
pass
try:
form1.element('select', _name=fname)['_disabled'] = 'true'
except:
pass
-----------------------------------------------------------------------------------------------------------------------------------------------

Anthony

unread,
Nov 29, 2016, 11:02:39 AM11/29/16
to web...@googlegroups.com
On Tuesday, November 29, 2016 at 8:52:07 AM UTC-5, Sundar wrote:
Yes- it looks very bad. I think the below method will work. (Let me know if you need any elaboration)

rofields = [db.<table>.field1, .....]
hidden = {}
for f in rofields:
fname = str(f).split('.')[1]
hidden[fname] = r[fname]
form1 = SQLFORM(db.<table>, record=<recid> , showid=True, hidden=hidden)

Note, to get the name of a field, just do field.name. Also, not sure why the hidden fields (SQLFORM won't do anything with their contents), and I don't see "r" defined anywhere.

Some simpler code to disable the form fields:

    [form1.element(_name=f.name).update(_disabled=True) for f in rofields]

An alternative approach is to change the widgets associated with read-only fields:

for field in db.mytable:
   
if field.readable and not field.writable:
        field.writable = True # So the widget will be used to display the value.
        field
.widget = lambda f, v: SQLFORM.widgets[field.type].widget(f, v, _readonly=True)
form
= SQLFORM(db.mytable, record).process()

Anthony

Sundar

unread,
Nov 30, 2016, 2:14:33 AM11/30/16
to web2py-users
Thanks, Anthony.

1. I thought f.name gives the name as <table>.<field> but for the hidden fields and form1.element, the field name alone is required. I will make a note of it.

2. hidden is included to make sure that the update back end operation does not make those fields as NULL. Not sure if the below alternatives will work: (a) using 'readonly' attribute so that the values go to the back end - but does it happen in all the browsers? (b) may be we can remove the disabled attribute just before submitting the form?)

3. I missed explaining r. r is the record from the database containing the values for all the selected record and I needed to set them as the values of the hidden field. r has been fetched before the below code in the function.

4. Simpler codes - noted and thanks a lot for the simplification.

Sundar
=========================================================================

On Tuesday, November 29, 2016 at 9:32:39 PM UTC+5:30, Anthony wrote:
On Tuesday, November 29, 2016 at 8:52:07 AM UTC-5, Sundar wrote:
Yes- it looks very bad. I think the below method will work. (Let me know if you need any elaboration)

rofields = [db.<table>.field1, .....]
hidden = {}
for f in rofields:
fname = str(f).split('.')[1]
hidden[fname] = r[fname]
form1 = SQLFORM(db.<table>, record=<recid> , showid=True, hidden=hidden)

Note, to get the name of a field, just do field.name. Also, not sure why the hidden fields (SQLFORM won't do anything with their contents), and I don't see "r" defined anywhere.

Some simpler code to disable the form fields:

    [form1.element(_name=f.name).update(_disabled=True) for f in rofields]

An alternative approach is to change the widgets associated with read-only fields:

for field in db.mytable:
   
if field.readable and not field.writable:

        field
.widget = lambda f, v: SQLFORM.widgets[field.type].widget(f, v, _disabled=True)
form
= SQLFORM(db.mytable, record).process()

Anthony

Anthony

unread,
Nov 30, 2016, 4:07:29 PM11/30/16
to web2py-users
2. hidden is included to make sure that the update back end operation does not make those fields as NULL. Not sure if the below alternatives will work: (a) using 'readonly' attribute so that the values go to the back end - but does it happen in all the browsers? (b) may be we can remove the disabled attribute just before submitting the form?)

Yes, but note that SQLFORM will not actually do anything with the values in the hidden fields, so you would have to write additional code to update form.vars with those values before processing the form.

Anthony

Bob St John

unread,
Nov 30, 2016, 6:42:43 PM11/30/16
to web2py-users

Pierre

unread,
Dec 1, 2016, 5:20:22 AM12/1/16
to web2py-users
It takes some javascript to make Anthony's solution work:
[
form1.element(_name=f.name).update(_disabled=True) for f in rofields]

disabled fields won't pass form validation without some js code in the corresponding view:
<script>
    jQuery
(document).ready(function() {
        $
( "[class|='form']" ).submit(function(){
        $
( ".form-control[disabled]" ).prop( "disabled", false );
});
   
});
</script>


Paolo Caruccio

unread,
Dec 1, 2016, 4:54:05 PM12/1/16
to web...@googlegroups.com
Try with
 
label.readonly~div{padding-top:7px;}

Anthony

unread,
Dec 1, 2016, 5:19:13 PM12/1/16
to web2py-users
On Thursday, December 1, 2016 at 5:20:22 AM UTC-5, Pierre wrote:
It takes some javascript to make Anthony's solution work:
[
form1.element(_name=f.name).update(_disabled=True) for f in rofields]

Note, I was just showing how to simplify some existing code there, but good point. In the alternative solution I proposed using the field's "widget" attribute, I switched to the "readonly" attribute, which does send back the value when the form is posted, so no Javascript necessary in that case (of course "readonly" could be used in place of "disabled" in the above solution as well).

Anthony

Pierre

unread,
Dec 2, 2016, 6:07:41 AM12/2/16
to web2py-users
the readonly prop doesn't prevent users from "messing-up" with the readonly fields and to change their values (reference fields) at list in the form:  not very clean user interface in my opinion......:(

 

Anthony

unread,
Dec 2, 2016, 9:11:48 AM12/2/16
to web2py-users
On Friday, December 2, 2016 at 6:07:41 AM UTC-5, Pierre wrote:
the readonly prop doesn't prevent users from "messing-up" with the readonly fields and to change their values (reference fields) at list in the form:  not very clean user interface in my opinion......:(

Yes, they do prevent the user from editing the values, that's the whole point of the "readonly" attribute. The fields can be focused, but not edited. In terms of the user interface, "readonly" is the same as "disabled", except the former can be focused, which can be a convenience, as it allows selection and therefore copying.

Anthony

Pierre

unread,
Dec 2, 2016, 12:37:44 PM12/2/16
to web...@googlegroups.com
sorry to insist Anthony
but the select tags (used for reference fields) are still editable with readonly="readonly"
your first option with  _disabled  works for me.....alignment is perfect and it's safe....


excerpt from  http://www.w3schools.com/tags/att_readonly.asp

Definition and Usage

The readonly attribute is a boolean attribute.

When present, it specifies that an input field or textarea is read-only.

A read-only field cannot be modified (however, a user can tab to it, highlight it, and copy the text from it).

The readonly attribute can be set to keep a user from changing the value until some other conditions have been met (like selecting a checkbox, etc.). Then, a JavaScript can remove the readonly value, and make the input field editable.


Applies to

The readonly attribute can be used on the following elements:

Elements Attribute
<input> readonly
<textarea> readonly


Anthony

unread,
Dec 2, 2016, 6:22:06 PM12/2/16
to web2py-users
On Friday, December 2, 2016 at 12:37:44 PM UTC-5, Pierre wrote:
sorry to insist Anthony
but the select tags (used for reference fields) are still editable with readonly="readonly"
your first option with  _disabled  works for me.....alignment is perfect and it's safe....

OK, got it -- yes, readonly doesn't apply to select fields, just input and textarea.

Actually, thinking about it further, Sundar's approach of using "disabled" and then copying the values to hidden fields with the same names should work (as long as they have the same names, I believe SQLFORM will process them as usual).

Anthony

Paolo Caruccio

unread,
Dec 2, 2016, 7:01:07 PM12/2/16
to web2py-users
My previous answer was too short. I was in a hurry. So I want elaborate it more.
Martin wrote to have an alignment problem between the label and the text that SQLFORM generates when the field is not writable.
Web2py in this context gives to the label of not writable field the css class "readonly" that not to be confused with the homonym html attribute.
bootstrap gives a padding-top 7 px to the label in a horizontal form and, in the case of a static control, suggests

When you need to place plain text form next to a label within at form, use the .form-control-static class on a <p>.

Therefore, in order to align the text to its label we could wrap the text in a <p> tag (maybe using javascript) having "form-control-static" class or assign a top padding of 7 px to the <div> that is sibling of the label in the rendered SQLForm

label.readonly ~ div {padding-top: 7px;}

of course the previous css rule goes in an extra .css file after bootstrap files.



Il giorno lunedì 21 novembre 2016 16:42:54 UTC+1, Martin de Groot ha scritto:
Reply all
Reply to author
Forward
0 new messages