Class: Forms::TagField
- Inherits:
-
Phlex::HTML
- Object
- Phlex::HTML
- Forms::TagField
- Includes:
- Phlex::Reactive::ClientBindings
- Defined in:
- lib/forms/tag_field.rb
Overview
A model-bound tag/chip input, composed from phlex-reactive's CLIENT-ONLY tag primitives (form state, no token, zero round trips). phlex-forms owns the polished chrome — daisyUI styling, model binding, the hidden comma-joined field — while phlex-reactive owns the behavior contract.
f.field :tags, as: :tags, suggestions: %w[Ruby Rails Hotwire Postgres]
f.field :tags, as: :tags, suggestions: { "Postgres" => "postgres database db sql" }
Submits ONE comma-joined param (user[tags] = "Ruby,Rails"), the primitive's
wire contract — the model splits it (an attribute :tags + a tags= writer,
or an ActiveModel array type).
This file is autoloaded ONLY when Phlex::Reactive is present (the Forms::Live gate in lib/phlex_forms.rb) because it includes ClientBindings at class level. The reactive_tags_* client helpers require phlex-reactive >= 0.11.4.
It uses the reactive_tags_add/option/remove helpers for the chip/query/option
behavior, but emits the ROOT's data-reactive-tags-field raw rather than via
reactive_tags(:tags): that helper compiles a SYMBOL through the class-level
reactive_scope, but a form builder's wire name is per-instance ("user").
The data attribute IS the public contract; any CSS selector works (issue #6
Caveats 1 & 2). Likewise the query input targets by #id so it never submits.
Direct Known Subclasses
Class Method Summary collapse
-
.root_tag_attributes(name:, id:) ⇒ Object
The root's tag wire attrs.
Instance Method Summary collapse
-
#initialize(*modifiers, name:, id:, value: nil, suggestions: [], error: false, placeholder: "Add a tag…", **attributes) ⇒ TagField
constructor
A new instance of TagField.
- #view_template ⇒ Object
Constructor Details
#initialize(*modifiers, name:, id:, value: nil, suggestions: [], error: false, placeholder: "Add a tag…", **attributes) ⇒ TagField
Returns a new instance of TagField.
29 30 31 32 33 34 35 36 37 38 39 40 |
# File 'lib/forms/tag_field.rb', line 29 def initialize(*modifiers, name:, id:, value: nil, suggestions: [], error: false, placeholder: "Add a tag…", **attributes) @modifiers = modifiers @name = name # "user[tags]" — instance-dynamic @id = id @value = value.is_a?(Array) ? value.compact.join(",") : value.to_s @suggestions = normalize_suggestions(suggestions) @error = error @placeholder = placeholder @attributes = attributes super() end |
Class Method Details
.root_tag_attributes(name:, id:) ⇒ Object
The root's tag wire attrs. Raw, not reactive_tags(:tags)/reactive_filter(:q) (Caveats 1 & 2): target the hidden field by [name=…] and the query input by #id (an id selector means the query input never submits a stray param). Public so Forms::Live can hoist these onto the
56 57 58 59 60 61 |
# File 'lib/forms/tag_field.rb', line 56 def self.root_tag_attributes(name:, id:) { data: { reactive_tags_field: %([name="#{name}"]), reactive_filter_input: "##{id}_query" } } end |
Instance Method Details
#view_template ⇒ Object
42 43 44 45 46 47 48 49 |
# File 'lib/forms/tag_field.rb', line 42 def view_template # Standalone: THIS div is the reactive root. Inside a Forms::Live form the # widget renders rootless (Forms::RootlessTagField) — the outer <form> is # the root and carries these tag attrs — so the form owns the hidden field. div(**mix(reactive_root(id: "#{@id}_widget"), root_tag_attributes, class: root_classes)) do body end end |