Forms
Usage
Anchor provides a custom Form Builder which renders components for form elements.
Use the anchor_form_with helper in your views:
<%= anchor_form_with model: User.new do |form| %> <%= form.label :name %> <%= form.text_field :name %> <%= form.error_message_for :name %><% end %>1. Labels
Labels will automatically be suffixed with (optional) when the field is not
required. If you want to opt-out of this behavior, you can pass required: true
on the label:
<%= anchor_form_with model: User.new do |form| %> <%= form.label :name, required: true %> <%= form.text_field :name %> <%= form.error_message_for :name %><% end %>2. Conditional Input Controller
The purpose of the conditional input controller is to specify an input (or multiple inputs) that triggers the display of a container (or containers) and its contents. The conditional input controller supports multiple inputs with both AND and OR logic.
Both the conditionalinputtarget: "input" and conditionalinputtarget: "container" attributes are required. The conditional_input_show_if attribute is added to the container element and is used to specify the conditions under which the container should be displayed.
<%= form.input :donor_id ... data: { action: "change->conditional-input#toggle", conditional_input_target: "input" } %><%= tag.div hidden: true, data: { conditional_input_target: "container", conditional_input_show_if: ... } %>To determine how to use the conditional_input_show_if attribute, you can refer to the examples below. Please note that single vs multiple inputs mean how many inputs have the conditional_input_target: "input" on them.
2.1. Limitations
- The input that triggers the display of the container can only be static values that can be matched with an "equals" condition. Things like dates, regex text, or other complex conditions are not supported.
- A field with multiple checkboxes has not been fully tested, but it should work as long as the values are static and can be matched with an "equals" condition.
2.2. conditional_input_show_if Attribute
This attribute must follow a very specific format.
conditional_input_show_if: [ { "<input_name1>": [<value1>", "<value2>", ...] } ]It is an array of objects, where each object represents a condition that must be met for the container to be displayed. Each object can contain one or more key-value pairs, where the key is the name of the input and the value is an array of values for that input that, if selected, will display the container.
2.2.1 OR Logic
In the example below, the container will be shown if the donor_id input is either "1", "2", or "3".
conditional_input_show_if: [ { "donor_id": ["1", "2", "3"] }]In the example below, the container will be shown if the donor_id input is either "1", "2", or "3" OR the donor_type input is "individual".
conditional_input_show_if: [ { "donor_id": ["1", "2", "3"] }, { "donor_type": ["individual"] }]2.2.2. AND Logic
In the example below, the container will be shown if the donor_id input is "1" AND the donor_type input is "individual".
conditional_input_show_if: [ { "donor_id": ["1"], "donor_type": ["individual"] }]2.2.3. AND + OR Logic
In the example below, the container will be shown if the donor_id input is "1", "2", or "3" AND the donor_type input is "individual" OR the donor_id input is "4", "5", or "6" AND the donor_type input is "organization".
conditional_input_show_if: [ { "donor_id": ["1", "2", "3"], "donor_type": ["individual"] }, { "donor_id": ["4", "5", "6"], "donor_type": ["organization"] }]3. Input Validation
If you would like to validate that your form is set up correctly, you can follow these steps.
- Open your browser's developer console, and paste the following code:
class ConditionalInputValidator { get inputTargets() { return Array.from(document.querySelectorAll('[data-conditional-input-target="input"]')); } get inputNames() { return this.inputTargets.map(input => input.getAttribute('name')); } get containerTargets() { return Array.from(document.querySelectorAll('[data-conditional-input-target="container"]')); } get conditionalInputs() { return this.containerTargets.map(container => { return container.getAttribute('data-conditional-input-show-if'); }); } generateSchema() { var validFieldSchema = { "type": "array", "minItems": 1, "uniqueItems": true, "items": { "allOf": [ { "type": "string" } ], } } console.log( JSON.stringify({ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "array", "items": { "type": "array", "items": { "type": "object", "properties": this.inputNames.reduce((acc, inputName) => { acc[inputName] = validFieldSchema; return acc; },{}) } } }, null, 2) ); } generateCode() { return this.conditionalInputs }}validator = new ConditionalInputValidator;Go to jsonlint.com and check the output of
validator.generateCode()to validate the JSON structure.Go to jsonschemavalidator.net. You'll see two panels. Paste the output of
validator.generateSchema()into the left panel. Paste the output ofvalidator.generateCode()into the right panel.