Add variant controller

This will manage the various unit fields. Maybe it should have a more specific name.
This commit is contained in:
David Cook
2024-03-18 17:04:46 +11:00
parent 9beaf0a0c2
commit c98956bf5a
3 changed files with 67 additions and 2 deletions

View File

@@ -61,12 +61,12 @@
- product.variants.each_with_index do |variant, variant_index|
= form.fields_for("products][#{product_index}][variants_attributes][", variant, index: variant_index) do |variant_form|
%tr.condensed
%tr.condensed{ 'data-controller': "variant" }
= render partial: 'variant_row', locals: { variant:, f: variant_form }
= form.fields_for("products][#{product_index}][variants_attributes][NEW_RECORD", product.variants.build) do |new_variant_form|
%template{ 'data-nested-form-target': "template" }
%tr.condensed
%tr.condensed{ 'data-controller': "variant" }
= render partial: 'variant_row', locals: { variant: new_variant_form.object, f: new_variant_form }
%tr{ 'data-nested-form-target': "target" }

View File

@@ -32,5 +32,7 @@ export default class ProductController extends Controller {
this.variantUnit.value = variant_unit_with_scale;
this.variantUnitScale.value = "";
}
this.variantUnit.dispatchEvent(new Event("change"));
this.variantUnitScale.dispatchEvent(new Event("change"));
}
}

View File

@@ -0,0 +1,63 @@
import { Controller } from "stimulus";
// Dynamically update related variant fields
//
export default class VariantController extends Controller {
connect() {
// Assuming these will be available on the variant soon, just a quick hack to find the product fields:
const product = this.element.closest("[data-record-id]");
this.variantUnit = product.querySelector('[name$="[variant_unit]"]');
this.variantUnitScale = product.querySelector('[name$="[variant_unit_scale]"]');
this.variantUnitName = product.querySelector('[name$="[variant_unit_name]"]');
this.unitValueWithDescription = this.element.querySelector(
'[name$="[unit_value_with_description]"]',
);
this.displayAs = this.element.querySelector('[name$="[display_as]"]');
this.unitToDisplay = this.element.querySelector('[name$="[unit_to_display]"]');
// on unit changed; update display_as:placeholder and unit_to_display
[this.variantUnit, this.variantUnitScale, this.variantUnitName].forEach((element) => {
element.addEventListener("change", this.#unitChanged.bind(this), { passive: true });
});
// on unit_value_with_description changed; update unit_value and unit_description
// on unit_value and/or unit_description changed; update display_as:placeholder and unit_to_display
this.unitValueWithDescription.addEventListener("input", this.#unitValueChanged.bind(this), {
passive: true,
});
// on display_as changed; update unit_to_display (how does this relate to unit_presentation?)
this.displayAs.addEventListener("input", this.#updateUnitDisplay.bind(this), { passive: true });
}
disconnect() {
// Make sure to clean up anything that happened outside
}
// private
// Extract variant_unit and variant_unit_scale from dropdown variant_unit_with_scale,
// and update hidden product fields
#unitChanged(event) {
//todo: deduplicate events.
//Hmm in hindsight the logic in product_controller should be inn this controller already. then we can do everything in one event, and store the generated name in an instance variable.
this.#updateUnitDisplay();
}
// Extract unit_value and unit_description from unit_value_with_description,
// and update hidden fields
#unitValueChanged(event) {
//todo: deduplicate events.
this.#updateUnitDisplay();
}
// Update display_as placeholder and unit_to_display
#updateUnitDisplay() {
// const unitDisplay = OptionValueNamer...
const unitDisplay =
this.unitValueWithDescription.value + " " + (this.variantUnitName.value || "~g"); //To Remove: DEMO only
this.displayAs.placeholder = unitDisplay;
this.unitToDisplay.textContent = this.displayAs.value || unitDisplay;
}
}