Mark tom-select as changed

Thankfully I was able to use basic DOM features, so there's no coupling of the logic with tom-select.

It wasn't going to be simple to get tom-select to listen for the 'changed' class on the original select, so I found a simple solution with a CSS sibling selector instead.
This commit is contained in:
David Cook
2024-02-29 12:20:50 +11:00
parent af748158aa
commit bfd6319cf2
3 changed files with 49 additions and 2 deletions

View File

@@ -1,6 +1,19 @@
import { Controller } from "stimulus";
// Manages "changed" state for a form with multiple records
// Manage "changed" state for a form with multiple records
//
// When any elements are changed:
// - the element is marked ".changed"
// - "actions" element appears
// - "changedSummary" element is updated using I18n
// - "disableSelector" elements are disabled
// - The browser will warn if trying to leave the page
//
// Supported element types:
// - input[type=text] and similar
// - input[type=checkbox]
// - select (single) - including tom-select
//
export default class BulkFormController extends Controller {
static targets = ["actions", "changedSummary"];
static values = {
@@ -113,6 +126,11 @@ export default class BulkFormController extends Controller {
#isChanged(element) {
if (element.type == "checkbox") {
return element.defaultChecked !== undefined && element.checked != element.defaultChecked;
} else if (element.type == "select-one") {
const defaultSelected = Array.from(element.options).find((opt)=>opt.hasAttribute('selected'));
return element.selectedOptions[0] != defaultSelected;
} else {
return element.defaultValue !== undefined && element.value != element.defaultValue;
}

View File

@@ -188,3 +188,12 @@
}
}
}
// Display as "changed" if sibling select is marked as changed.
select.changed + .ts-wrapper {
&.single, &.multi {
.ts-control {
border-color: $color-txt-changed-brd;
}
}
}

View File

@@ -36,6 +36,10 @@ describe("BulkFormController", () => {
<div data-record-id="1">
<input id="input1a" type="text" value="initial1a">
<input id="input1b" type="text" value="initial1b">
<select id="select1">
<option>one</option>
<option selected>two</option>
</select>
<button>a button is counted as a form element, but value is undefined</button>
</div>
<div data-record-id="2">
@@ -47,7 +51,7 @@ describe("BulkFormController", () => {
});
describe("marking changed fields", () => {
it("onInput", () => {
it("input: onInput", () => {
input1a.value = 'updated1a';
input1a.dispatchEvent(new Event("input"));
// Expect only first field to show changed
@@ -59,7 +63,23 @@ describe("BulkFormController", () => {
input1a.value = 'initial1a';
input1a.dispatchEvent(new Event("input"));
expect(input1a.classList).not.toContain('changed');
});
it("select: onInput", () => {
// Select a different option (it's the only way in Jest..)
select1.options[0].selected = true;
select1.options[1].selected = false;
select1.dispatchEvent(new Event("input"));
// Expect select to show changed
expect(input1a.classList).not.toContain('changed');
expect(input1b.classList).not.toContain('changed');
expect(select1.classList).toContain('changed');
// Change back to original value
select1.options[0].selected = false;
select1.options[1].selected = true;
select1.dispatchEvent(new Event("input"));
expect(select1.classList).not.toContain('changed');
});
it("multiple fields", () => {