'disabled' widgets mode [ Plone 6 classic ]

Is there a 'uneditable' widgets mode ?
or should this be done another way (on field, maybe)?

I can use

.mode = interfaces.HIDDEN_MODE

Works, but does not show in edit mode

.mode = interfaces.DISPLAY_MODE

Not editable in edit mode, but saves as 'empty' (removing what was there).


UPDATE: For now, I have come up with this 'ugly hack':

    group.description = '{}<br/><p>My Field Name</p><input disabled class="form-control" value="{}"/>'.format(group.description , group.widgets['my_field'].value)
    group.widgets['my_field'].mode = interfaces.HIDDEN_MODE

from plone.z3cform.fieldsets.utils import remove

you can remove a field from a form based on conditions

This way as I understand it different conditions can change what is shown for edit - and without removing already saved values of the field that was there

I want the field to be editable in addForm, but in EditForm I want it to (just) show,

Does anyone know if 'disabled' is supposed to be set on wigets?

# Works
#group.widgets['initial_due_date'].mode = interfaces.DISPLAY_MODE

#Gives zope.schema._bootstrapinterfaces.ConstraintNotSatisfied: (True, 'disabled')
group.widgets['initial_due_date'].disabled=True
group.widgets['initial_due_date'].disabled='True'
group.widgets['initial_due_date'].disabled=1

Strangely enough,

group.widgets['initial_due_date'].disabled='disabled' 

Produces no error (but has no impact')

This is because there's the widget attribute definition in z3c.form but a missing implementation in the plone.app.z3cform template. You could override the template with z3c.jbot and add the attribute or you try the newest version of plone.app.z3cform · PyPI 4.4.0 with the new extensible widget attribute implementation which should set this attribute in the input widget template automatically. See this PR for details Update widget templates with newest `z3c.form` extendable attributes. by petschki · Pull Request #181 · plone/plone.app.z3cform · GitHub

PS: by set attribute, I assume it would be something like this:

group.widgets['some_field'].disabled=1  (or True)

I pinned to >= 4.4.0 (and updated from 6.0.6 to 6.0.7), but result was the same. Maybe there are some other add-ons that needs to be pinned to ?

I gave this a quick shot with a custom behavior here using p.a.z3cform==4.3.0 (no generic attribute feature)

  1. General disabled field:
from plone.autoform.interfaces import IFormFieldProvider
from plone.autoform import directives
from plone.supermodel import model
from z3c.form.browser.text import TextFieldWidget
from zope.interface import Interface
from zope.interface import provider


class ITestDisabledFieldMarker(Interface):
    pass


@provider(IFormFieldProvider)
class ITestDisabledField(model.Schema):
    """
    """

    project = schema.TextLine(
        title=_(u'Project'),
        description=_(u'Give in a project name'),
        required=False,
    )
    directives.widget(
        "project",
        TextFieldWidget,
        disabled="disabled",
    )

This now shows a disabled input field in my form when the behavior is enabled somewhere:

  1. Only on @@edit view:

Remove the directives.widget in the schema above and customize the edit view.
Note that there's already a customized edit view in p.a.z3cform

from plone.app.z3cform.views import EditForm
from plone.dexterity.interfaces import IDexterityEditForm
from plone.z3cform import layout
from zope.interface import implementer

@implementer(IDexterityEditForm)
class CustomEditForm(EditForm):
    def updateWidgets(self):
        super().updateWidgets()
        self.widgets["ITestDisabledField.project"].disabled = "disabled"


CustomEditView = layout.wrap_form(CustomEditForm)

and wire this in zcml. Overriding the @@edit view needs a custom layer or a custom object marker:

    <browser:page
          name="edit"
          for=".test_disabled_field.ITestDisabledFieldMarker"
          class=".test_disabled_field.CustomEditView"
          permission="cmf.ModifyPortalContent"
          layer="plone.app.z3cform.interfaces.IPloneFormLayer"
          />

now the add form has this field enabled and the editform disabled (with the value from the addform)

Extranote: The overridden @@edit view from p.a.z3cform is obsolete and got removed in >=4.4.0 so it gets simpler to override this one in the future.

Thanks, it works with 'default fieldset'.

Need to check (later) why 'group' matters, since I also have this in another fieldset, where this did not work:

    def update(self):
        super(MyContentTypeEditForm, self).update()

        for group in self.groups:
            if group.__name__ == 'some_fieldset':
                 group.widgets['my_field'].disabled='disabled'

Probably, it needs to be done somewhere else (than def update)

So far, it does not seem like it matters where this is 'updated', it 'just does not work for fieldsets'.
Note setting .mode (instead of .disabled) works, so maybe it is a bug somewhere (?)

There's an upcoming documentation for this topic. Especially the widgets section Widgets – Backend — Plone Documentation v6.0

Would love to here your feedback on this ideally in this PR: add classic-ui: forms, fields, schemas, content types by MrTango · Pull Request #1461 · plone/documentation · GitHub

Basically, I think this is 'how I have done it', but the disabled setting does not work for fieldsets (groups)

So, this works in 'for group in self.groups:'

  group.widgets[Imyfield'].mode = HIDDEN_MODE

but group.widgets[Imyfield'].disabled does not

For default fieldset, 'everything works'.

I will try to find out why and post feedback later.

I just had this once more in a project of mine and I have more details on this. The following code snipped (basically copied from the docs here Forms – Classic UI — Plone Documentation v6.0 and extended it) has a default and a personal_info fieldset.

from plone import schema
from plone.app.z3cform.widgets.datetime import DateFieldWidget
from plone.autoform import directives
from plone.autoform.form import AutoExtensibleForm
from plone.supermodel.directives import fieldset
from z3c.form import button
from z3c.form import form
from z3c.form.browser.text import TextFieldWidget
from zope.interface import Interface


class IMyForm(Interface):
    """ Schema Interface for IMyForm
        Define your form fields here.
    """

    # field in default fieldset
    test_field = schema.TextLine(
        title="Default Field"
    )

    fieldset(
        "personal_info",
        label="Personal Information",
        fields=["name", "surname", "birthday"],
    )

    name = schema.TextLine(
        title="Your name",
    )

    surname = schema.TextLine(
        title="Your surname",
    )
    directives.widget(
        "surname",
        TextFieldWidget,
        disabled="disabled",
    )

    birthday = schema.Date(
        title="Birthday",
    )
    directives.widget(
        "birthday",
        DateFieldWidget,
        disabled="disabled",
    )


class MyForm(AutoExtensibleForm, form.EditForm):
    schema = IMyForm
    ignoreContext = True

This generates a disabled TextFieldWidget on the second tab, but the DateFieldWidget is not disabled.

This is because the "pattern widget" implementation in plone.app.z3cform misses this property obviously. So this doesn't have anything to do with auto extensible group forms but with widget template implementation in p.a.z3cform.

I've tested this with latest plone.app.z3cform==4.4.0 and z3c.form==5.1 and with a minimal change to the import (to get Bootstrap TextFieldWidget):

from plone.app.z3cform.widgets.text import TextFieldWidget

it works for both fields as expected:

1 Like

Thanks a lot, I did not think of that.

Just for the record: it was not possible to change wiget template either – that was the workaround I (also) tried ( .template = Z3ViewPageTemplateFile("some.pt") )

Quickly tried that with:

class MyForm(AutoExtensibleForm, form.EditForm):
    schema = IMyForm
    ignoreContext = True

    def update(self):
        super().update()
        self.groups[0].widgets["birthday"].template = ViewPageTemplateFile("templates/test_widget.pt")

and it worked... nice to know.

There might be a caveat with disabled fields because this doesn't get submitted in the request AFAIK. So if you have a prefilled disabled field in the edit form, the field might be emptied if you save that form. But I didn't test that.

For a long time ago, i run in this issue, no value in the data record with a disabled form field

Perhaps instead of the disabled attribute, y'all would want the readonly attribute? Compare:

Readonly works but has the same problem.

It looks like some things can not be set from views / EditForm .

For example, a richtext field does not seem to 'respond to anything'.
In fact, if set the mode to 'HIDDEN', it hides the label, but nothing else

If anyone has a suggestion on how to disable input to a rich text field, please let me know.

I have tried the following

  • change mode
  • disable
  • readonly
  • change template
  • add CSS class

Maybe it can be hacked around by CSS pointer or adding a javascript, but it would be better to do somehing else.

Alternatively: register a new widget for input (?)

I can confirm that latest version (of Plone) works with

self.widgets['bodytext'].mode = interfaces.DISPLAY_MODE

For richtext field.
I am 'on my way for vacation' so I have not closed any issues.