`;
}
override updated(changedProps: any) {
if (changedProps.has('name')) {
// set name for each checkbox
this.checkboxes.forEach((checkbox: any) => {
checkbox.name = this.name;
});
}
if (changedProps.has('value')) {
this._validate(false, false);
// set checked state for each checkbox
this.checkboxes.forEach((checkbox: any) => {
checkbox.checked = this.value.includes(checkbox.value);
});
const CheckedBoxesCount = this.checkboxes.filter(
(checkbox) => checkbox.checked
).length;
// sync "Select All" checkbox state
this.selectAllChecked = CheckedBoxesCount === this.checkboxes.length;
// sync "Select All" indeterminate state
this.selectAllIndeterminate =
CheckedBoxesCount < this.checkboxes.length && CheckedBoxesCount > 0;
// set form data value
// const entries = new FormData();
// this.value.forEach((value) => {
// entries.append(this.name, value);
// });
// this.internals.setFormValue(entries);
}
if (changedProps.has('required')) {
// set required for each checkbox
this.checkboxes.forEach((checkbox: any) => {
checkbox.required = this.required;
});
}
if (changedProps.has('disabled')) {
// set disabled for each checkbox
this.checkboxes.forEach((checkbox: any) => {
checkbox.disabled = this.disabled;
});
}
if (
changedProps.has('invalidText') &&
changedProps.get('invalidText') !== undefined
) {
this._validate(false, false);
}
if (
changedProps.has('invalidText') ||
changedProps.has('internalValidationMsg')
) {
this.isInvalid =
this.invalidText !== '' || this.internalValidationMsg !== ''
? true
: false;
// set invalid state for each checkbox
this.checkboxes.forEach((checkbox: any) => {
checkbox.invalid = this.isInvalid;
});
}
if (changedProps.has('limitCheckboxes')) {
this._toggleRevealed(false);
}
}
private _validate(interacted: Boolean, report: Boolean) {
// set validity flags
const Validity = {
customError: this.invalidText !== '',
valueMissing: this.required && !this.value.length,
};
// set validationMessage
const InternalMsg =
this.required && !this.value.length ? 'A selection is required.' : '';
const ValidationMessage =
this.invalidText !== '' ? this.invalidText : InternalMsg;
// set validity on custom element, anchor to first checkbox
this.internals.setValidity(Validity, ValidationMessage, this.checkboxes[0]);
// set internal validation message if value was changed by user input
if (interacted) {
this.internalValidationMsg = InternalMsg;
}
// focus the first checkbox to show validity
if (report) {
this.internals.reportValidity();
}
}
private _handleCheckboxChange(e: any) {
const value = e.detail.value;
if (value === 'selectAll') {
if (e.detail.checked) {
this.value = this.checkboxes
.filter((checkbox) => !checkbox.disabled)
.map((checkbox) => {
return checkbox.value;
});
} else {
this.value = [];
}
} else {
const newValues = [...this.value];
if (newValues.includes(value)) {
const index = newValues.indexOf(value);
newValues.splice(index, 1);
} else {
newValues.push(value);
}
this.value = newValues;
}
this._validate(true, false);
this._emitChangeEvent();
}
private _emitChangeEvent() {
const event = new CustomEvent('on-checkbox-group-change', {
detail: { value: this.value },
});
this.dispatchEvent(event);
}
private _handleFormdata(e: any) {
this.value.forEach((value) => {
e.formData.append(this.name, value);
});
}
private _handleFilter(e: any) {
let visibleCount = 0;
this.searchTerm = e.detail.value.toLowerCase();
this.checkboxes.forEach((checkboxEl) => {
// get checkbox label text
const nodes = checkboxEl.shadowRoot.querySelector('slot').assignedNodes({
flatten: true,
});
let checkboxText = '';
for (let i = 0; i < nodes.length; i++) {
checkboxText += nodes[i].textContent.trim();
}
// hide checkbox if no match to search term
if (this.limitCheckboxes && !this.limitRevealed) {
if (
checkboxText.toLowerCase().includes(this.searchTerm) &&
visibleCount < 4
) {
checkboxEl.style.display = 'block';
visibleCount++;
} else {
checkboxEl.style.display = 'none';
}
} else {
if (checkboxText.toLowerCase().includes(this.searchTerm)) {
checkboxEl.style.display = 'block';
} else {
checkboxEl.style.display = 'none';
}
}
});
}
private _toggleRevealed(revealed: boolean) {
const Limit = 4;
this.limitRevealed = revealed;
this.searchTerm = '';
this.checkboxes.forEach((checkboxEl, index) => {
if (!this.limitCheckboxes || this.limitRevealed) {
checkboxEl.style.display = 'block';
} else {
if (index < Limit) {
checkboxEl.style.display = 'block';
} else {
checkboxEl.style.display = 'none';
}
}
});
}
private _handleSlotChange() {
this.requestUpdate();
}
private _handleInvalid() {
this._validate(true, false);
}
override connectedCallback() {
super.connectedCallback();
// capture child checkboxes change event
this.addEventListener('on-checkbox-change', (e: any) =>
this._handleCheckboxChange(e)
);
if (this.internals.form) {
this.internals.form.addEventListener('formdata', (e) =>
this._handleFormdata(e)
);
this.addEventListener('invalid', () => {
this._handleInvalid();
});
}
}
override disconnectedCallback() {
this.removeEventListener('on-checkbox-change', (e: any) =>
this._handleCheckboxChange(e)
);
if (this.internals.form) {
this.internals.form.removeEventListener('formdata', (e) =>
this._handleFormdata(e)
);
this.removeEventListener('invalid', () => {
this._handleInvalid();
});
}
super.disconnectedCallback();
}
}
declare global {
interface HTMLElementTagNameMap {
'kyn-checkbox-group': CheckboxGroup;
}
}