Add a readonly field to Easyform

Hi!

is is possible to add a read only field to Easyform? My use case it to display something in the form (at the begin of the form for example) based on some site parameters. I can have a text field with a default value but it is rendered as an input field. The label and advanced label fields ignores the override fields, they're just static.

Given that

		<field name="intro_text" 
                          type="zope.schema.TextLine">
			<default>My text</default>
			<readonly>True</readonly>
	    </field>

causes the field to not be displayed, I would use some custom CSS to apply your "read-only "styling and use a default factory to populate the field.

		<field name="intro_text" 
                          type="zope.schema.TextLine"
                          easyform:css_class="textline-readonly">
			  <defaultFactory>my_package.interfaces.intro_text_default</defaultFactory>
	    </field>

EDIT, you want to use form:mode

<field form:mode="display" name="intro_text" type="zope.schema.TextLine" >
			<default>My text</default>
	    </field>
1 Like

Thanks!

This is my defaultFactory:

@provider(IDefaultFactory)
def intro_text_default(self):
    return 'AAA'

It works but there's no parameter in the function... no self, context or other else.

if I do:

@provider(IContextAwareDefaultFactory)
def intro_text_default(context):
    return 'AAA' + str(context)

context is None, this prints 'AAANone'

but with breakpoint():

utils.py(143)intro_text_default()
-> return 'AAA' + str(context)
(Pdb) pp context
<EasyForm at /xxxx/myform>
(Pdb) pp str(context)
<EasyForm at /xxxx/myform>

:-/

I see you are already using IContextAwareDefaultFactory - maybe you have to get the context "out of thin air" with getSite()or its plone.api equivalent?

I get it. The defaultFactory is called 3 times. The first 2 time context is there, the third one (the one used by the model) returns None. So I get None at the end.

This is my supermodel xml:

    <field form:mode="display" name="intro_text" type="zope.schema.TextLine" easyform:css_class="textline-readonly">
      <defaultFactory>myaddon.utils.intro_text_default</defaultFactory>
    </field>

(rendering the dexterity control panel, the function is called 2 times, not 3.

in the dexterity ttw field editor I get as default value:
AAA

Be aware that modifying the form with the GUI will replace the factory with its static value.

Continuing in the debugger, I end here after the third call:
zope/schema/_bootstrapfields.py(108)

103  	        if IContextAwareDefaultFactory.providedBy(defaultFactory):
104  	            value = defaultFactory(inst.context)
105  	        else:
106  	            value = defaultFactory()

Also adding alsoProvides(IContextAwareDefaultFactory) inside the function does not work, I always get None at the end.

Be aware that modifying the form with the GUI will replace the factory with its static value.

I saved the xml directly and it is still there.

:-/

I tend to short-circuit these types of deep z3c.form mysteries with something like (or similar):

from zope.globalrequest import getRequest

def getContext():
    request = getRequest()
    published = request.get("PUBLISHED", None)
    context = getattr(published, "__parent__", None)

    return context
2 Likes

Using getContext above works!

The question is: why you Plone are you asking me contextaware this and that, while context and request are already there? LOL

Looking at the code seems a problem of easyform superAdapter. Also the code is called 3 times... magic of widget "update()".

Anyway thanks!

1 Like

Happy it worked!

Try this with a DataGridField... Better not!