Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hide widget instead of deleting it #11

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open

Conversation

nerdoc
Copy link

@nerdoc nerdoc commented Nov 26, 2023

fixes #4

@j4mie
Copy link
Member

j4mie commented Nov 29, 2023

Hiding a field and removing it from the form are two very different things, so I can't merge this change as it would be very backwards-incompatible.

I'd recommend just dynamically setting the widget for the field. If you want to do this a lot, abstract it into a little utility function. Maybe something like this (untested):

def hidden_if(predicate):
    def get_widget(form):
        if predicate(form):
            return forms.HiddenInput()
    return get_widget


class CancellationReasonForm(DynamicFormMixin, forms.Form):
    ...
    reason_if_other = DynamicField(
        forms.CharField,
        widget=hidden_if(lambda form: form["cancellation_reason"].value() != "other"),
    )

@nerdoc
Copy link
Author

nerdoc commented Nov 30, 2023

ok, understand. I found another way which allows removing it from the form. And you are right, I played through all versions of hiding, deleting and disabling a widget, and it always breaks things.
I then eded up in making it configureable within DynamicFormMixin, so you have this three options.
Hiding the widget does not make sense in most of the situations, but disabling the widget could make sense in a dynamic form.
If you are interested in that idea:

class ExcludeMethod:     # or (Enum): # or (IntegerChoices) (which is overkill)
    HIDE = 0
    DELETE = 1
    DISABLE = 2

class MyDynamicFormMixin:
    class Meta:
        excluded_fields_method = ExcludeMethod.HIDE

    def __init__(self, *args, **kwargs):
        self.context = kwargs.pop("context", None)
        super().__init__(*args, **kwargs)

        for name, field in list(self.fields.items()):
            if isinstance(field, DynamicField):
                if field.should_be_included(self):
                    self.fields[name] = field.make_real_field(self)
                else:
                    excluded_fields_method = (
                        self.Meta.excluded_fields_method
                        if (hasattr(self.Meta, "excluded_fields_method"))
                        else (ExcludeMethod.HIDE)
                    )
                    if excluded_fields_method == ExcludeMethod.DELETE:
                        del self.fields[name]
                    elif excluded_fields_method == ExcludeMethod.HIDE:
                        self.fields[name].widget = self.fields[name].hidden_widget()
                        self.fields[name].required = False
                    elif excluded_fields_method == ExcludeMethod.DISABLE:
                        self.fields[name].disabled = True
                    else:
                        raise ValueError(
                            f"Invalid value for 'excluded_fields_method': {excluded_fields_method}"
                        )

It's working code, but not really tested. But you get the idea.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support for crispy forms with custom layouts
2 participants