mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-03-01 02:03:22 +00:00
Toggle input disabled when on demand checked
This introduces a new 'toggle' controller, and we already had three\! So I created a generic interface that could be extended to potentially support all of them. I propose we try to reduce them all into the one controller, but won't go down the rabbit-hole just yet.. I have an idea on how to re-arrange and make it more contained, by assigning the controller only to the checkbox, and defining targets with aria-controls="", but chose to stick with Stimulus conventions for now.
This commit is contained in:
@@ -88,13 +88,13 @@
|
||||
%td.field.on-hand__wrapper{'data-controller': "popout"}
|
||||
%button.on-hand__button{'data-popout-target': "button"}
|
||||
= variant.on_demand ? t(:on_demand) : variant.on_hand
|
||||
%div.on-hand__popout{ style: 'display: none;', 'data-popout-target': "dialog"}
|
||||
%div.on-hand__popout{ style: 'display: none;', 'data-controller': 'toggle-control', 'data-popout-target': "dialog" }
|
||||
.field
|
||||
= variant_form.number_field :on_hand, 'aria-label': t('admin.products_page.columns.on_hand')
|
||||
= variant_form.number_field :on_hand, 'aria-label': t('admin.products_page.columns.on_hand'), 'data-toggle-control-target': 'control', disabled: variant_form.object.on_demand
|
||||
= error_message_on variant, :on_hand
|
||||
.field.checkbox
|
||||
= variant_form.label :on_demand do
|
||||
= variant_form.check_box :on_demand, 'data-action': 'change->popout#closeIfChecked'
|
||||
= variant_form.check_box :on_demand, 'data-action': 'change->toggle-control#disableIfPresent change->popout#closeIfChecked'
|
||||
= t('admin.products_page.columns.on_demand')
|
||||
%td.align-left
|
||||
.content= variant.product.supplier&.name # same as product
|
||||
|
||||
33
app/webpacker/controllers/toggle_control_controller.js
Normal file
33
app/webpacker/controllers/toggle_control_controller.js
Normal file
@@ -0,0 +1,33 @@
|
||||
import { Controller } from "stimulus";
|
||||
|
||||
export default class extends Controller {
|
||||
static targets = ["control"];
|
||||
|
||||
disableIfPresent(event) {
|
||||
const input = event.currentTarget;
|
||||
const disable = !!this.#inputValue(input); // Coerce value to boolean
|
||||
|
||||
this.controlTargets.forEach((target) => {
|
||||
target.disabled = disable;
|
||||
});
|
||||
|
||||
// Focus when enabled
|
||||
if (!disable) {
|
||||
this.controlTargets[0].focus();
|
||||
}
|
||||
}
|
||||
|
||||
//todo: can a new method disableIfBlank replace ButtonDisabledController?
|
||||
//todo: can a new method toggleDisplay replace ToggleController?
|
||||
//todo: can toggleDisplay with optional chevron-target replace RemoteToggleController?
|
||||
|
||||
// private
|
||||
|
||||
// Return input's value, but only if it would be submitted by a form
|
||||
// Radio buttons not supported (yet)
|
||||
#inputValue(input) {
|
||||
if (input.type != "checkbox" || input.checked) {
|
||||
return input.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
70
spec/javascripts/stimulus/toggle_control_controller_test.js
Normal file
70
spec/javascripts/stimulus/toggle_control_controller_test.js
Normal file
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* @jest-environment jsdom
|
||||
*/
|
||||
|
||||
import { Application } from "stimulus";
|
||||
import toggle_controller from "../../../app/webpacker/controllers/toggle_control_controller";
|
||||
|
||||
describe("ToggleControlController", () => {
|
||||
beforeAll(() => {
|
||||
const application = Application.start();
|
||||
application.register("toggle-control", toggle_controller);
|
||||
});
|
||||
|
||||
describe("#disableIfPresent", () => {
|
||||
describe("with checkbox", () => {
|
||||
beforeEach(() => {
|
||||
document.body.innerHTML = `<div data-controller="toggle-control">
|
||||
<input id="checkbox" type="checkbox" value="1" data-action="change->toggle-control#disableIfPresent" />
|
||||
<input id="control" data-toggle-control-target="control">
|
||||
</div>`;
|
||||
|
||||
const checkbox = document.getElementById("checkbox");
|
||||
const control = document.getElementById("control");
|
||||
});
|
||||
|
||||
it("Disables when checkbox is checked", () => {
|
||||
checkbox.click();
|
||||
expect(checkbox.checked).toBe(true);
|
||||
|
||||
expect(control.disabled).toBe(true);
|
||||
});
|
||||
|
||||
it("Enables when checkbox is un-checked", () => {
|
||||
checkbox.click();
|
||||
checkbox.click();
|
||||
expect(checkbox.checked).toBe(false);
|
||||
|
||||
expect(control.disabled).toBe(false);
|
||||
});
|
||||
});
|
||||
describe("with input", () => {
|
||||
beforeEach(() => {
|
||||
document.body.innerHTML = `<div data-controller="toggle-control">
|
||||
<input id="input" value="" data-action="input->toggle-control#disableIfPresent" />
|
||||
<input id="control" data-toggle-control-target="control">
|
||||
</div>`;
|
||||
|
||||
const input = document.getElementById("input");
|
||||
const control = document.getElementById("control");
|
||||
});
|
||||
|
||||
it("Disables when input is filled", () => {
|
||||
input.value = "test"
|
||||
input.dispatchEvent(new Event("input"));
|
||||
|
||||
expect(control.disabled).toBe(true);
|
||||
});
|
||||
|
||||
it("Enables when input is emptied", () => {
|
||||
input.value = "test"
|
||||
input.dispatchEvent(new Event("input"));
|
||||
|
||||
input.value = ""
|
||||
input.dispatchEvent(new Event("input"));
|
||||
|
||||
expect(control.disabled).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user