Conditional Fields in Dexterity Schema

Hi Community,

I have the special case of a conditional field in my dexterity content type at the moment. The parent object has an attribute (bool, yes/no) and I need to show/hide a field in the child content type depending on this (parent)attribute. In AT Types there was a condition-attribute on the field to handle something like that, but I couldn't figure out a way in dx.

Any suggestions?

1 Like

Here is some related discussion

There is perhaps (some complex) way to solve this on the Python layer however I do prefer Javascript
hackery here. What we usually do in such situations is having a viewlet that injects additional markup with data-attributes (in this case the information from the parent object) into the HTML of the Plone site and then some custom JS doing the hide/no-hide magic based on the value of such a data attribute...makes sense?

Should this happen in a normal View or on creation in the add/edit form?
You can traverse up to site root or only to the parent and check the property or behavior. If the boolvalue is 'True' do what you want in your child. But i don't know how "expensive" is that way.

# traverse up
# from plone.app.layout root.py
def getNavigationRootObject(context, portal):
    obj = context
    while not INavigationRoot.providedBy(obj) and aq_base(obj) is not aq_base(portal):
        parent = aq_parent(aq_inner(obj))
        if parent is None:
            return obj
        obj = parent
    return obj

Since the appearance of your field is not dependent on another field in the same form, you could override the add/edit form and see if you can mess around with with the schema's a bit. Or maybe swapping out the widget for the field with a 'no display/null)' version of the widget based on the field value of the parent will be enough so you don't have to touch the schema as well.

https://docs.plone.org/external/plone.app.dexterity/docs/advanced/custom-add-and-edit-forms.html

Dexterity content types are dynamic in the sense that you can (re)define them through the web, but the changeability on a single instance is not well deveoped and/or documented with easy options, you have to go deep into dexterity itself.

Let us know which solution you have found.

That's really easy.
Register a custom form and override the widget:

<browser:page
    name="edit"
    for="my.site.content.foo.IFoo"
    layer="my.site.interfaces.IMySiteLayer"
    class=".foo.FooEditForm"
    permission="cmf.ModifyPortalContent"
    />
# -*- coding: utf-8 -*-
from plone.dexterity.browser import edit

class FooEditForm(edit.DefaultEditForm):

    def updateWidgets(self):
        super(FooEditForm, self).updateWidgets()
        parent = self.context.__parent__
        if getattr(parent, 'whatever', None):
            self.widgets['description'].mode = 'hidden'

The same works with addforms as well but is a bit different:

<adapter
    for="Products.CMFCore.interfaces.IFolderish
         my.site.interfaces.IMySiteLayer
         plone.dexterity.interfaces.IDexterityFTI"
    provides="zope.publisher.interfaces.browser.IBrowserPage"
    factory=".foo.AddView"
    name="foo"
    />
<class class=".foo.AddView">
    <require
        permission="cmf.AddPortalContent"
        interface="zope.publisher.interfaces.browser.IBrowserPage"
        />
</class>

and the form:

from plone.dexterity.browser import add

class AddForm(add.DefaultAddForm):
    portal_type = 'foo'

    def updateWidgets(self):
        super(AddForm, self).updateWidgets()
        if getattr(self.context, 'whatever', None):
            self.widgets['description'].mode = 'hidden'

class AddView(add.DefaultAddView):
    form = AddForm
3 Likes

Thanks for the implementation @pbauer :wink: