Skip to content

Commit 6fae62f

Browse files
authored
Fix conditional fields (#91)
1 parent 6e21a14 commit 6fae62f

File tree

2 files changed

+66
-71
lines changed

2 files changed

+66
-71
lines changed

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,14 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
1616

1717
## Unreleased
1818

19+
### Fixed
20+
21+
- Conditional fields not working properly when there are multiple elements inspecting the same driving field [#91]
22+
23+
### Removed
24+
25+
- IE11 support [#91]
26+
1927
## [3.0.0](https://github.com/torchbox/tbxforms/releases/tag/v3.0.0)
2028

2129
### Developer

tbxforms/static/js/tbxforms.js

Lines changed: 58 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,48 @@
11
import '../sass/tbxforms.scss';
22

33
/**
4-
* CustomEvent polyfill for IE11.
5-
* https://stackoverflow.com/a/26596324/1798491
4+
* Updates the visibility of a form element based on conditional field values
5+
* @param {HTMLElement} container - The container element to show/hide
6+
* @param {NodeList} drivingFieldNodeList - List of form fields that control visibility
7+
* @param {Array} conditionalValuesForElement - Values that should trigger showing the container
68
*/
7-
(function () {
8-
if (typeof window.CustomEvent === 'function') return false; //If not IE
9-
10-
function CustomEvent(event, params) {
11-
params = params || { bubbles: false, cancelable: false, detail: undefined };
12-
var evt = document.createEvent('CustomEvent');
13-
evt.initCustomEvent(
14-
event,
15-
params.bubbles,
16-
params.cancelable,
17-
params.detail
18-
);
19-
return evt;
9+
function updateVisibility(
10+
container,
11+
drivingFieldNodeList,
12+
conditionalValuesForElement
13+
) {
14+
let shouldShow = false;
15+
16+
if (drivingFieldNodeList.length > 1) {
17+
// For checkboxes/radios, check if any are checked with matching values
18+
drivingFieldNodeList.forEach(function (field) {
19+
if (field.checked && conditionalValuesForElement.includes(field.value)) {
20+
shouldShow = true;
21+
}
22+
});
23+
} else {
24+
// For single fields, check the value directly
25+
const field = drivingFieldNodeList.item(0);
26+
shouldShow =
27+
conditionalValuesForElement.includes(field.value) ||
28+
conditionalValuesForElement.includes(Number(field.value));
2029
}
2130

22-
CustomEvent.prototype = window.Event.prototype;
23-
24-
window.CustomEvent = CustomEvent;
25-
})();
31+
// Update visibility and aria states
32+
container.hidden = !shouldShow;
33+
drivingFieldNodeList.forEach((field) =>
34+
field.setAttribute('aria-expanded', shouldShow.toString())
35+
);
36+
}
2637

38+
/**
39+
* Initializes form functionality with conditional field visibility
40+
* @param {HTMLFormElement} form - The form element to initialize
41+
* @constructor
42+
*/
2743
function TbxForms(form) {
28-
this.form = form;
44+
this.form = form; // Stash the TbxForms DOM element.
45+
const self = this; // Stash the TbxForms instance.
2946

3047
// Loop through all elements within the given form (e.g. inputs, divs, fieldsets).
3148
form.querySelectorAll('*').forEach(function (formElement) {
@@ -42,7 +59,6 @@ function TbxForms(form) {
4259
);
4360
let conditionalValuesForElement;
4461

45-
// Try to parse the JSON containing required field mapping.
4662
try {
4763
conditionalValuesForElement = JSON.parse(
4864
formElement.dataset.conditionalFieldValues
@@ -53,55 +69,31 @@ function TbxForms(form) {
5369

5470
container.classList.add('tbxforms-conditional');
5571

56-
if (drivingFieldNodeList.length > 1) {
57-
// We're dealing with radios or checkboxes.
58-
59-
drivingFieldNodeList.forEach(function (option_node) {
60-
option_node.addEventListener('change', function () {
61-
if (
62-
option_node.checked &&
63-
conditionalValuesForElement.includes(option_node.value)
64-
) {
65-
option_node.setAttribute('aria-expanded', 'true');
66-
container.hidden = false;
67-
} else {
68-
option_node.setAttribute('aria-expanded', 'false');
69-
container.hidden = true;
70-
}
71-
});
72-
73-
// Trigger above event listener to correct presentation.
74-
option_node.dispatchEvent(new CustomEvent('change'));
75-
});
76-
} else {
77-
// We're dealing with a single field.
78-
79-
const drivingField = drivingFieldNodeList.item(0);
80-
81-
drivingField.addEventListener('change', function () {
82-
if (
83-
conditionalValuesForElement.includes(drivingField.value) ||
84-
conditionalValuesForElement.includes(Number(drivingField.value))
85-
) {
86-
drivingField.setAttribute('aria-expanded', 'true');
87-
container.hidden = false;
88-
} else {
89-
drivingField.setAttribute('aria-expanded', 'false');
90-
container.hidden = true;
91-
}
72+
// Set up change listeners
73+
drivingFieldNodeList.forEach(function (field) {
74+
field.addEventListener('change', function () {
75+
updateVisibility(
76+
container,
77+
drivingFieldNodeList,
78+
conditionalValuesForElement
79+
);
9280
});
81+
});
9382

94-
// Trigger above event listener to correct presentation.
95-
drivingField.dispatchEvent(new CustomEvent('change'));
96-
}
83+
// Check initial state
84+
updateVisibility(
85+
container,
86+
drivingFieldNodeList,
87+
conditionalValuesForElement
88+
);
9789
}
9890
});
9991

10092
// Clear any values for fields that are conditionally hidden.
10193
// NB. We don't use `form.elements.('[hidden]')` to include divs.
10294
form.addEventListener('submit', function () {
10395
form.querySelectorAll('[hidden]').forEach(function (hiddenFormElement) {
104-
form.clearInput(hiddenFormElement);
96+
self.clearInput(hiddenFormElement);
10597
});
10698
});
10799
}
@@ -144,10 +136,8 @@ TbxForms.prototype.clearInput = function (node) {
144136
break;
145137

146138
default:
147-
console.error(
148-
"Unexpected node.type '" +
149-
node.type +
150-
"' found while trying to clearInput."
139+
console.debug(
140+
`Skipping unsupported node.type '${node.type}' while trying to clearInput().`
151141
);
152142
}
153143
break;
@@ -160,8 +150,7 @@ TbxForms.prototype.clearInput = function (node) {
160150
node.selectedIndex = -1;
161151
break;
162152

163-
// If this is a container element run again for child elements.
164-
// NB. maybe a `default` case would be better here.
153+
// If this is a container element, run again for child elements.
165154
case 'DIV':
166155
case 'FIELDSET':
167156
node.querySelectorAll('*').forEach(function (formElement) {
@@ -170,10 +159,8 @@ TbxForms.prototype.clearInput = function (node) {
170159
break;
171160

172161
default:
173-
console.error(
174-
"Unexpected node.tagName '" +
175-
node.tagName +
176-
"' found while trying to clearInput."
162+
console.debug(
163+
`Skipping unsupported node.tagName '${node.tagName}' while trying to clearInput().`
177164
);
178165
}
179166
};

0 commit comments

Comments
 (0)