Skip to content

Add conditional logic to Fields with tests #95

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

Merged
merged 5 commits into from
Feb 26, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion tbxforms/layout/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
from .base import Layout
from .base import (
Layout,
setup_conditional_attrs,
)
from .buttons import (
Button,
Submit,
Expand Down Expand Up @@ -30,4 +33,5 @@
"Layout",
"Size",
"Submit",
"setup_conditional_attrs",
]
22 changes: 22 additions & 0 deletions tbxforms/layout/base.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,27 @@
import json

from crispy_forms import layout as crispy_forms_layout


class Layout(crispy_forms_layout.Layout):
pass


def setup_conditional_attrs(kwargs: dict):
"""
Set up our flat attributes to handle conditional field/container logic.

As an example, this will transform:
{ "data_conditional": { "field_name": "trigger_field", "values": ["yes", "no"] } }
to:
{ "data_conditional_field_name": "trigger_field", "data_conditional_field_values": "[\"yes\", \"no\"]" }
""" # noqa: E501

conditional_attrs = kwargs.pop("data_conditional", None)
if conditional_attrs:
kwargs["data_conditional_field_name"] = conditional_attrs["field_name"]
kwargs["data_conditional_field_values"] = json.dumps(
conditional_attrs["values"]
)

return kwargs
25 changes: 6 additions & 19 deletions tbxforms/layout/containers.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import json

from django.template.loader import render_to_string

from crispy_forms import layout as crispy_forms_layout
Expand All @@ -8,7 +6,10 @@
flatatt,
)

from tbxforms.layout import Size
from tbxforms.layout import (
Size,
setup_conditional_attrs,
)


class Div(crispy_forms_layout.Div):
Expand Down Expand Up @@ -47,14 +48,7 @@ class Div(crispy_forms_layout.Div):
"""

def __init__(self, *fields, **kwargs):
if "data_conditional" in kwargs:
conditional_attrs = kwargs.pop("data_conditional")
kwargs["data_conditional_field_name"] = conditional_attrs[
"field_name"
]
kwargs["data_conditional_field_values"] = json.dumps(
conditional_attrs["values"]
)
kwargs = setup_conditional_attrs(kwargs=kwargs)
super().__init__(*fields, **kwargs)


Expand Down Expand Up @@ -128,14 +122,7 @@ def __init__(
if not hasattr(self, "css_class"):
self.css_class = kwargs.pop("css_class", None)

if "data_conditional" in kwargs:
conditional_attrs = kwargs.pop("data_conditional")
kwargs["data_conditional_field_name"] = conditional_attrs[
"field_name"
]
kwargs["data_conditional_field_values"] = json.dumps(
conditional_attrs["values"]
)
kwargs = setup_conditional_attrs(kwargs=kwargs)

self.css_id = kwargs.pop("css_id", None)
self.template = kwargs.pop("template", self.template)
Expand Down
23 changes: 14 additions & 9 deletions tbxforms/layout/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
Fixed,
Fluid,
Size,
setup_conditional_attrs,
)


Expand Down Expand Up @@ -421,16 +422,20 @@ def add_attributes(self, **kwargs):

Args:
**kwargs: keyword arguments that will be added as HTML attributes.

Returns:

"""
self.attrs.update(
{
k.replace("_", "-"): conditional_escape(v)
for k, v in kwargs.items()
}
)
kwargs = setup_conditional_attrs(kwargs=kwargs)

for k, v in kwargs.items():
# Don't escape values that are already JSON encoded
if k in [
"data_conditional_field_name",
"data_conditional_field_values",
]:
value = v
else:
value = conditional_escape(v)

self.attrs.update({k.replace("_", "-"): value})

def render(
self,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<form class="tbxforms" method="post">
<div id="div_id_test_field" class="tbxforms-form-group">
<label for="id_test_field" class="tbxforms-label tbxforms-label--m">Test field</label>
<select name="test_field" class="selectmultiple" id="id_test_field" multiple>
<option value="yes">Yes</option>
<option value="no">No</option>
</select>
</div>
</form>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<form class="tbxforms" method="post">
<div id="div_id_test_field" class="tbxforms-form-group">
<label for="id_test_field" class="tbxforms-label tbxforms-label--m">Test field</label>
<select name="test_field" class="tbxforms-select" id="id_test_field">
<option value="yes">Yes</option>
<option value="no">No</option>
</select>
</div>
</form>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<form class="tbxforms" method="post">
<div id="div_id_test_field" class="tbxforms-form-group">
<label for="id_test_field" class="tbxforms-label tbxforms-label--m">Test field</label>
<select name="test_field" class="tbxforms-select" id="id_test_field">
<option value="yes">Yes</option>
<option value="no">No</option>
</select>
</div>
</form>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<form class="tbxforms" method="post">
<div id="div_id_test_field" class="tbxforms-form-group">
<label for="id_test_field" class="tbxforms-label tbxforms-label--m">Test field</label>
<input type="text"
name="test_field"
class="tbxforms-input tbxforms-input--text"
id="id_test_field">
</div>
</form>
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<form class="tbxforms" method="post">
<div id="div_id_test_field" class="tbxforms-form-group">
<label for="id_test_field" class="tbxforms-label tbxforms-label--m">Test field</label>
<input type="text"
name="test_field"
rows="10"
class="tbxforms-input tbxforms-input--text"
id="id_test_field">
</div>
</form>
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<form class="tbxforms" method="post">
<div class="tbxforms-form-group"
data-conditional-field-name="trigger_field"
data-conditional-field-values="[&quot;yes&quot;]">
<div id="div_id_field1" class="tbxforms-form-group">
<label for="id_field1" class="tbxforms-label tbxforms-label--m">Field1</label>
<input type="text"
name="field1"
class="tbxforms-input tbxforms-input--text"
required="required"
id="id_field1">
</div>
<div id="div_id_field2" class="tbxforms-form-group">
<label for="id_field2" class="tbxforms-label tbxforms-label--m">Field2</label>
<input type="text"
name="field2"
class="tbxforms-input tbxforms-input--text"
required="required"
id="id_field2">
</div>
</div>
</form>
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<form class="tbxforms" method="post">
<fieldset class="tbxforms-form-group tbxforms-fieldset"
data-conditional-field-name="trigger_field"
data-conditional-field-values="[&quot;yes&quot;]">
<div id="div_id_field1" class="tbxforms-form-group">
<label for="id_field1" class="tbxforms-label tbxforms-label--m">Field1</label>
<input type="text"
name="field1"
class="tbxforms-input tbxforms-input--text"
required="required"
id="id_field1">
</div>
<div id="div_id_field2" class="tbxforms-form-group">
<label for="id_field2" class="tbxforms-label tbxforms-label--m">Field2</label>
<input type="text"
name="field2"
class="tbxforms-input tbxforms-input--text"
required="required"
id="id_field2">
</div>
</fieldset>
</form>
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<form class="tbxforms" method="post">
<div class="tbxforms-form-group"
data-conditional-field-name="trigger_field"
data-conditional-field-values="[&quot;yes&quot;, &quot;maybe&quot;]">
<div id="div_id_field1" class="tbxforms-form-group">
<label for="id_field1" class="tbxforms-label tbxforms-label--m">Field1</label>
<input type="text"
name="field1"
class="tbxforms-input tbxforms-input--text"
required="required"
id="id_field1">
</div>
</div>
</form>
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<form class="tbxforms" method="post">
<fieldset class="tbxforms-form-group tbxforms-fieldset"
data-conditional-field-name="trigger_field"
data-conditional-field-values="[&quot;yes&quot;, &quot;maybe&quot;]">
<div id="div_id_field1" class="tbxforms-form-group">
<label for="id_field1" class="tbxforms-label tbxforms-label--m">Field1</label>
<input type="text"
name="field1"
class="tbxforms-input tbxforms-input--text"
required="required"
id="id_field1">
</div>
</fieldset>
</form>
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<form class="tbxforms" method="post">
<div id="div_id_trigger_field" class="tbxforms-form-group">
<div class="tbxforms-checkboxes">
<div class="tbxforms-checkboxes__item">
<input type="checkbox"
name="trigger_field"
class="tbxforms-checkboxes__input"
required="required"
id="id_trigger_field">
<label class="tbxforms-label tbxforms-checkboxes__label"
for="id_trigger_field">Trigger field</label>
</div>
</div>
</div>
<div id="div_id_dependent_field" class="tbxforms-form-group">
<div class="tbxforms-checkboxes">
<div class="tbxforms-checkboxes__item">
<input type="checkbox"
name="dependent_field"
data-conditional-field-name="trigger_field"
data-conditional-field-values="[true]"
class="tbxforms-checkboxes__input"
id="id_dependent_field">
<label class="tbxforms-label tbxforms-checkboxes__label"
for="id_dependent_field">Dependent field</label>
</div>
</div>
</div>
</form>
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<form class="tbxforms" method="post">
<div id="div_id_trigger_field" class="tbxforms-form-group">
<div class="tbxforms-checkboxes">
<div class="tbxforms-checkboxes__item">
<input type="checkbox"
name="trigger_field"
class="tbxforms-checkboxes__input"
required="required"
id="id_trigger_field">
<label class="tbxforms-label tbxforms-checkboxes__label"
for="id_trigger_field">Trigger field</label>
</div>
</div>
</div>
<div id="div_id_dependent_field" class="tbxforms-form-group">
<label for="id_dependent_field" class="tbxforms-label tbxforms-label--m">
Dependent field
<span class="tbxforms-field_marker--optional">(optional)</span>
</label>
<select name="dependent_field"
data-conditional-field-name="trigger_field"
data-conditional-field-values="[true]"
class="selectmultiple"
id="id_dependent_field"
multiple>
<option value="yes">Yes</option>
<option value="no">No</option>
</select>
</div>
</form>
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<form class="tbxforms" method="post">
<div id="div_id_trigger_field" class="tbxforms-form-group">
<div class="tbxforms-checkboxes">
<div class="tbxforms-checkboxes__item">
<input type="checkbox"
name="trigger_field"
class="tbxforms-checkboxes__input"
required="required"
id="id_trigger_field">
<label class="tbxforms-label tbxforms-checkboxes__label"
for="id_trigger_field">Trigger field</label>
</div>
</div>
</div>
<div id="div_id_dependent_field" class="tbxforms-form-group">
<label for="id_dependent_field" class="tbxforms-label tbxforms-label--m">
Dependent field
<span class="tbxforms-field_marker--optional">(optional)</span>
</label>
<select name="dependent_field"
data-conditional-field-name="trigger_field"
data-conditional-field-values="[true]"
class="tbxforms-select"
id="id_dependent_field">
<option value="yes">Yes</option>
<option value="no">No</option>
</select>
</div>
</form>
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<form class="tbxforms" method="post">
<div id="div_id_trigger_field" class="tbxforms-form-group">
<div class="tbxforms-checkboxes">
<div class="tbxforms-checkboxes__item">
<input type="checkbox"
name="trigger_field"
class="tbxforms-checkboxes__input"
required="required"
id="id_trigger_field">
<label class="tbxforms-label tbxforms-checkboxes__label"
for="id_trigger_field">Trigger field</label>
</div>
</div>
</div>
<div id="div_id_dependent_field" class="tbxforms-form-group">
<label for="id_dependent_field" class="tbxforms-label tbxforms-label--m">
Dependent field
<span class="tbxforms-field_marker--optional">(optional)</span>
</label>
<select name="dependent_field"
data-conditional-field-name="trigger_field"
data-conditional-field-values="[true]"
class="tbxforms-select"
id="id_dependent_field">
<option value="yes">Yes</option>
<option value="no">No</option>
</select>
</div>
</form>
Loading