Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for block in collections (checkboxes & radio buttons) #148

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ module Form
class CollectionCheckBoxesComponent < FieldComponent
attr_reader :collection, :value_method, :text_method, :html_options

# IDEA: maybe we can use a slot here to render the collection items?
# renders_many :collection_items

def initialize( # rubocop:disable Metrics/ParameterLists
form,
object_name,
Expand Down Expand Up @@ -34,8 +37,7 @@ def call # rubocop:disable Metrics/MethodLength
value_method,
text_method,
options,
html_options,
&content
html_options
).render
end

Expand All @@ -45,6 +47,26 @@ def set_html_options!
@html_options[:class] = class_names(html_options[:class], html_class)
@html_options.delete(:class) if @html_options[:class].blank?
end

# See: https://github.com/rails/rails/blob/83217025a171593547d1268651b446d3533e2019/actionview/lib/action_view/helpers/tags/collection_helpers.rb#L89
def builder
@builder ||= begin
ActionView::Helpers::Tags::CollectionCheckBoxes::CheckBoxBuilder.new(@view_context, object_name, method_name, object, sanitize_attribute_name(value), text, value, input_html_options)
end
end
delegate :translation, to: :builder

def sanitize_attribute_name(value)
"#{sanitized_method_name}_#{sanitized_value(value)}"
end

def sanitized_method_name
@sanitized_method_name ||= @method_name.delete_suffix("?")
end

def sanitized_value(value)
value.to_s.gsub(/[\s.]/, "_").gsub(/[^-[[:word:]]]/, "").downcase
end
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,7 @@ def call # rubocop:disable Metrics/MethodLength
value_method,
text_method,
options,
html_options,
&content
html_options
).render
end

Expand Down
11 changes: 11 additions & 0 deletions lib/view_component/form/helpers/collection_helpers.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# frozen_string_literal: true

module ViewComponent
module Form
module Helpers
module CollectionHelpers
# TODO: put common logic between CollectionCheckBoxesComponent and CollectionRadioButtonsComponent here
end
end
end
end
1 change: 1 addition & 0 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
Combustion.initialize!(*modules) do
config.logger = ActiveSupport::TaggedLogging.new(Logger.new(nil))
config.log_level = :fatal
config.capture_compatibility_patch_enabled = true
end

require "generator_spec"
Expand Down
43 changes: 43 additions & 0 deletions spec/view_component/form/collection_check_boxes_component_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,49 @@
end
end

context "with a block" do
let(:block) do
proc do |c|
c.builder.label { c.builder.check_box + c.builder.text }
end
end

it do
expect(component).to eq_html <<~HTML
<input type="hidden" name="user[nationalities][]" value="" autocomplete="off"><label for="user_nationalities_be"><input type="checkbox" value="BE" name="user[nationalities][]" id="user_nationalities_be">Belgium</label><label for="user_nationalities_fr"><input type="checkbox" value="FR" name="user[nationalities][]" id="user_nationalities_fr">France</label>
HTML
end
end

# context "with a block and translation param" do
# let(:block) do
# proc do |component|
# "<span class=\"translated-label\">#{component.translation}</span>".html_safe
# end
# end

# it do
# expect(component).to eq_html <<~HTML
# <label for="user_first_name"><span class="translated-label">First name</span></label>
# HTML
# end
# end

# context "with a block and builder param" do
# let(:block) do
# proc do |component|
# "<span class=\"translated-label#{" has-error" if component.builder.object.errors.include?(:first_name)}\">" \
# "#{component.builder.translation}</span>".html_safe
# end
# end

# it do
# expect(component).to eq_html <<~HTML
# <label for="user_first_name"><span class="translated-label">First name</span></label>
# HTML
# end
# end

include_examples "component with custom html classes", :html_options
include_examples "component with custom data attributes", :html_options
end