Skip to content
Open
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
5 changes: 0 additions & 5 deletions .yarnrc

This file was deleted.

30 changes: 15 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1490,38 +1490,38 @@ Generated HTML:
<form accept-charset="UTF-8" action="/users" class="new_user" id="new_user" method="post">
<div class="mb-3">
<label class="form-label required" for="user_email">Email</label>
<input class="form-control is-invalid" id="user_email" name="user[email]" required="required" type="email" value="steve.example.com">
<div class="invalid-feedback">is invalid</div>
<input aria-labelledby="user_email_feedback" class="form-control is-invalid" id="user_email" name="user[email]" required="required" type="email" value="steve.example.com">
<div class="invalid-feedback" id="user_email_feedback">is invalid</div>
</div>
<div class="mb-3">
<label class="form-label" for="user_misc">Misc</label>
<div class="form-check">
<input checked class="form-check-input is-invalid" id="user_misc_1" name="user[misc]" type="radio" value="1">
<input aria-labelledby="user_misc_feedback" checked class="form-check-input is-invalid" id="user_misc_1" name="user[misc]" type="radio" value="1">
<label class="form-check-label" for="user_misc_1">Mind reading</label>
</div>
<div class="form-check">
<input class="form-check-input is-invalid" id="user_misc_2" name="user[misc]" type="radio" value="2">
<input aria-labelledby="user_misc_feedback" class="form-check-input is-invalid" id="user_misc_2" name="user[misc]" type="radio" value="2">
<label class="form-check-label" for="user_misc_2">Farming</label>
<div class="invalid-feedback">is invalid</div>
<div class="invalid-feedback" id="user_misc_feedback">is invalid</div>
</div>
</div>
<input id="user_preferences" name="user[preferences][]" type="hidden" value="">
<div class="mb-3">
<label class="form-label" for="user_preferences">Preferences</label>
<div class="form-check">
<input checked class="form-check-input is-invalid" id="user_preferences_1" name="user[preferences][]" type="checkbox" value="1">
<input aria-labelledby="user_preferences_feedback" checked class="form-check-input is-invalid" id="user_preferences_1" name="user[preferences][]" type="checkbox" value="1">
<label class="form-check-label" for="user_preferences_1">Good</label>
</div>
<div class="form-check">
<input class="form-check-input is-invalid" id="user_preferences_2" name="user[preferences][]" type="checkbox" value="2">
<input aria-labelledby="user_preferences_feedback" class="form-check-input is-invalid" id="user_preferences_2" name="user[preferences][]" type="checkbox" value="2">
<label class="form-check-label" for="user_preferences_2">Bad</label>
<div class="invalid-feedback">is invalid</div>
<div class="invalid-feedback" id="user_preferences_feedback">is invalid</div>
</div>
</div>
<div class="mb-3">
<label class="form-label" for="user_address_attributes_street">Street</label>
<input class="form-control is-invalid" id="user_address_attributes_street" name="user[address_attributes][street]" type="text" value="Bar">
<div class="invalid-feedback">is invalid</div>
<input aria-labelledby="user_address_attributes_street_feedback" class="form-control is-invalid" id="user_address_attributes_street" name="user[address_attributes][street]" type="text" value="Bar">
<div class="invalid-feedback" id="user_address_attributes_street_feedback">is invalid</div>
</div>
</form>
```
Expand Down Expand Up @@ -1551,8 +1551,8 @@ Generated HTML:
```html
<form accept-charset="UTF-8" action="/users" class="new_user" id="new_user" method="post">
<div class="mb-3">
<label class="form-label required text-danger" for="user_email">Email is invalid</label>
<input class="form-control is-invalid" id="user_email" name="user[email]" required="required" type="email" value="steve.example.com">
<label class="form-label required text-danger" for="user_email" id="user_email_feedback">Email is invalid</label>
<input aria-labelledby="user_email_feedback" class="form-control is-invalid" id="user_email" name="user[email]" required="required" type="email" value="steve.example.com">
</div>
</form>
```
Expand Down Expand Up @@ -1649,7 +1649,7 @@ Which outputs:
```html
<form accept-charset="UTF-8" action="/users" class="new_user" id="new_user" method="post">
<input autocomplete="off" class="is-invalid" disabled type="hidden">
<div class="invalid-feedback">Email is invalid</div>
<div class="invalid-feedback" id="user_email_feedback">Email is invalid</div>
</form>
```

Expand All @@ -1670,7 +1670,7 @@ Which outputs:
```html
<form accept-charset="UTF-8" action="/users" class="new_user" id="new_user" method="post">
<input autocomplete="off" class="is-invalid" disabled type="hidden">
<div class="invalid-feedback">is invalid</div>
<div class="invalid-feedback" id="user_email_feedback">is invalid</div>
</form>
```

Expand All @@ -1689,7 +1689,7 @@ Which outputs:
```html
<form accept-charset="UTF-8" action="/users" class="new_user" id="new_user" method="post">
<input autocomplete="off" class="is-invalid" disabled type="hidden">
<div class="custom-error">Email is invalid</div>
<div class="custom-error" id="user_email_feedback">Email is invalid</div>
</form>
```

Expand Down
1 change: 1 addition & 0 deletions lib/bootstrap_form/components/labels.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ def generate_label(id, name, options, custom_label_col, group_layout)

options[:class] = label_classes(name, options, custom_label_col, group_layout)
options.delete(:class) if options[:class].none?
options[:id] = field_id(name, :feedback) if error?(name) && label_errors

label(name, label_text(name, options), options.except(:text))
end
Expand Down
2 changes: 1 addition & 1 deletion lib/bootstrap_form/components/validation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ def generate_error(name)
help_klass = "invalid-feedback"
help_tag = :div

content_tag(help_tag, help_text, class: help_klass)
content_tag(help_tag, help_text, class: help_klass, id: field_id(name, :feedback))
end

def get_error_messages(name)
Expand Down
5 changes: 4 additions & 1 deletion lib/bootstrap_form/form_group_builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,10 @@ def form_group_css_options(method, html_options, options)
# Add control_class; allow it to be overridden by :control_class option
control_classes = css_options.delete(:control_class) { control_class }
css_options[:class] = safe_join([control_classes, css_options[:class]].compact, " ")
css_options[:class] << " is-invalid" if error?(method)
if error?(method)
css_options[:class] << " is-invalid"
css_options[:aria] = { labelledby: field_id(method, :feedback) }
end
css_options[:placeholder] = form_group_placeholder(options, method) if options[:label_as_placeholder]
css_options
end
Expand Down
2 changes: 1 addition & 1 deletion lib/bootstrap_form/helpers/bootstrap.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def errors_on(name, options={})
hide_attribute_name = options[:hide_attribute_name] || false
custom_class = options[:custom_class] || false

tag.div class: custom_class || "invalid-feedback" do
tag.div(class: custom_class || "invalid-feedback", id: field_id(name, :feedback)) do
errors = if hide_attribute_name
object.errors[name]
else
Expand Down
1 change: 1 addition & 0 deletions lib/bootstrap_form/inputs/check_box.rb
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ def check_box_options(name, options)
:inline, :label, :label_class, :label_col, :layout, :skip_label,
:switch, :wrapper, :wrapper_class)
check_box_options[:class] = check_box_classes(name, options)
check_box_options[:aria] = { labelledby: field_id(name, :feedback) } if error?(name)
check_box_options.merge!(required_field_options(options, name))
end

Expand Down
1 change: 1 addition & 0 deletions lib/bootstrap_form/inputs/radio_button.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ def radio_button_options(name, options)
radio_button_options = options.except(:class, :label, :label_class, :error_message, :help,
:inline, :hide_label, :skip_label, :wrapper, :wrapper_class)
radio_button_options[:class] = radio_button_classes(name, options)
radio_button_options[:aria] = { labelledby: field_id(name, :feedback) } if error?(name)
radio_button_options.merge!(required_field_options(options, name))
end

Expand Down
16 changes: 8 additions & 8 deletions test/bootstrap_checkbox_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -543,13 +543,13 @@ class BootstrapCheckboxTest < ActionView::TestCase
<div class="mb-3">
<label class="form-label" for="user_misc">Misc</label>
<div class="form-check">
<input class="form-check-input is-invalid" id="user_misc_1" name="user[misc][]" type="checkbox" value="1" />
<input class="form-check-input is-invalid" id="user_misc_1" aria-labelledby="user_misc_feedback" name="user[misc][]" type="checkbox" value="1" />
<label class="form-check-label" for="user_misc_1">Foo</label>
</div>
<div class="form-check">
<input class="form-check-input is-invalid" id="user_misc_2" name="user[misc][]" type="checkbox" value="2" />
<input class="form-check-input is-invalid" id="user_misc_2" aria-labelledby="user_misc_feedback" name="user[misc][]" type="checkbox" value="2" />
<label class="form-check-label" for="user_misc_2">Bar</label>
<div class="invalid-feedback">a box must be checked</div>
<div class="invalid-feedback" id="user_misc_feedback">a box must be checked</div>
</div>
</div>
</form>
Expand Down Expand Up @@ -593,13 +593,13 @@ class BootstrapCheckboxTest < ActionView::TestCase
<div class="mb-3">
<label class="form-label" for="user_misc">Misc</label>
<div class="form-check">
<input checked="checked" class="form-check-input is-invalid" id="user_misc_1" name="user[misc][]" type="checkbox" value="1" />
<input checked="checked" class="form-check-input is-invalid" id="user_misc_1" aria-labelledby="user_misc_feedback" name="user[misc][]" type="checkbox" value="1" />
<label class="form-check-label" for="user_misc_1"> Foo</label>
</div>
<div class="form-check">
<input checked="checked" class="form-check-input is-invalid" id="user_misc_2" name="user[misc][]" type="checkbox" value="2" />
<input checked="checked" class="form-check-input is-invalid" id="user_misc_2" aria-labelledby="user_misc_feedback" name="user[misc][]" type="checkbox" value="2" />
<label class="form-check-label" for="user_misc_2"> Bar</label>
<div class="invalid-feedback">error for test</div>
<div class="invalid-feedback" id="user_misc_feedback">error for test</div>
</div>
</div>
</form>
Expand All @@ -617,11 +617,11 @@ class BootstrapCheckboxTest < ActionView::TestCase
<form accept-charset="UTF-8" action="/users" class="new_user" id="new_user" method="post">
<div class="form-check mb-3">
<input #{autocomplete_attr} name="user[terms]" type="hidden" value="0" />
<input class="form-check-input is-invalid" id="user_terms" name="user[terms]" type="checkbox" value="1" />
<input class="form-check-input is-invalid" id="user_terms" aria-labelledby="user_terms_feedback" name="user[terms]" type="checkbox" value="1" />
<label class="form-check-label" for="user_terms">
I agree to the terms
</label>
<div class="invalid-feedback">You must accept the terms.</div>
<div class="invalid-feedback" id="user_terms_feedback">You must accept the terms.</div>
</div>
</form>
HTML
Expand Down
2 changes: 1 addition & 1 deletion test/bootstrap_fields_for_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ class BootstrapFieldsForTest < ActionView::TestCase
<form accept-charset="UTF-8" action="/users" class="new_user" id="new_user" method="post">
<div class="mb-3">
<label class="form-label required" for="address_city">City</label>
<input class="form-control is-invalid" id="address_city" name="address[city]" type="text" required="required" />
<input class="form-control is-invalid" id="address_city" aria-labelledby="address_city_feedback" name="address[city]" type="text" required="required" />
<!-- No `<div class="invalid-feedback">can't be blank</div>` -->
</div>
</form>
Expand Down
8 changes: 4 additions & 4 deletions test/bootstrap_fields_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,8 @@ class BootstrapFieldsTest < ActionView::TestCase
<form accept-charset="UTF-8" action="/users" class="new_user" enctype="multipart/form-data" id="new_user" method="post">
<div class="mb-3">
<label class="form-label" for="user_misc">Misc</label>
<input class="form-control is-invalid" id="user_misc" name="user[misc]" type="file"/>
<div class="invalid-feedback">error for test</div>
<input class="form-control is-invalid" id="user_misc" aria-labelledby="user_misc_feedback" name="user[misc]" type="file"/>
<div class="invalid-feedback" id="user_misc_feedback">error for test</div>
</div>
</form>
HTML
Expand All @@ -108,8 +108,8 @@ class BootstrapFieldsTest < ActionView::TestCase
<form accept-charset="UTF-8" action="/users" class="new_address" id="new_address" method="post">
<div class="mb-3">
<label class="form-label required" for="address_user_id">User</label>
<input class="form-control is-invalid" id="address_user_id" name="address[user_id]" required="required" type="text"/>
<div class="invalid-feedback">must exist</div>
<input class="form-control is-invalid" id="address_user_id" aria-labelledby="address_user_id_feedback" name="address[user_id]" required="required" type="text"/>
<div class="invalid-feedback" id="address_user_id_feedback">must exist</div>
</div>
</form>
HTML
Expand Down
42 changes: 10 additions & 32 deletions test/bootstrap_form_group_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -187,9 +187,9 @@ class BootstrapFormGroupTest < ActionView::TestCase
<label class="form-label required" for="user_email">Email</label>
<div class="input-group">
<span class="input-group-text">$</span>
<input required="required" class="form-control is-invalid" id="user_email" name="user[email]" type="text" />
<input required="required" class="form-control is-invalid" id="user_email" aria-labelledby="user_email_feedback" name="user[email]" type="text" />
<span class="input-group-text">.00</span>
<div class="invalid-feedback">can't be blank, is too short (minimum is 5 characters)</span>
<div class="invalid-feedback" id="user_email_feedback">can't be blank, is too short (minimum is 5 characters)</span>
</div>
</div>
</form>
Expand Down Expand Up @@ -434,28 +434,6 @@ class BootstrapFormGroupTest < ActionView::TestCase
assert_equivalent_html expected, output
end

test 'upgrade doc for form_group renders the "error" class and message correctly when object is invalid' do
@user.email = nil
assert @user.invalid?

output = @builder.form_group :email do
html = '<p class="form-control-plaintext">Bar</p>'.html_safe
unless @user.errors[:email].empty?
html << tag.div(@user.errors[:email].join(", "), class: "invalid-feedback",
style: "display: block;")
end
html
end

expected = <<~HTML
<div class="mb-3">
<p class="form-control-plaintext">Bar</p>
<div class="invalid-feedback" style="display: block;">can't be blank, is too short (minimum is 5 characters)</div>
</div>
HTML
assert_equivalent_html expected, output
end

test "upgrade doc for form_group renders check box correctly when object is invalid" do
@user.errors.add(:misc, "Must select one.")

Expand All @@ -471,17 +449,17 @@ class BootstrapFormGroupTest < ActionView::TestCase
<form accept-charset="UTF-8" action="/users" class="new_user" id="new_user" method="post">
<div class="mb-3">
<div class="form-check">
<input class="form-check-input is-invalid" id="user_misc_primary_school" name="user[misc]" type="radio" value="primary school"/>
<input class="form-check-input is-invalid" id="user_misc_primary_school" aria-labelledby="user_misc_feedback" name="user[misc]" type="radio" value="primary school"/>
<label class="form-check-label" for="user_misc_primary_school">Primary school</label>
</div>
<div class="form-check">
<input class="form-check-input is-invalid" id="user_misc_high_school" name="user[misc]" type="radio" value="high school"/>
<input class="form-check-input is-invalid" id="user_misc_high_school" aria-labelledby="user_misc_feedback" name="user[misc]" type="radio" value="high school"/>
<label class="form-check-label" for="user_misc_high_school">High school</label>
</div>
<div class="form-check">
<input class="form-check-input is-invalid" id="user_misc_university" name="user[misc]" type="radio" value="university"/>
<input class="form-check-input is-invalid" id="user_misc_university" aria-labelledby="user_misc_feedback" name="user[misc]" type="radio" value="university"/>
<label class="form-check-label" for="user_misc_university">University</label>
<div class="invalid-feedback">Must select one.</div>
<div class="invalid-feedback" id="user_misc_feedback">Must select one.</div>
</div>
</div>
</form>
Expand Down Expand Up @@ -509,9 +487,9 @@ class BootstrapFormGroupTest < ActionView::TestCase
<label class="form-label required" for="user_email">Email</label>
</div>
<div class="field_with_errors">
<input required="required" class="form-control is-invalid" id="user_email" name="user[email]" type="email" />
<input required="required" class="form-control is-invalid" id="user_email" aria-labelledby="user_email_feedback" name="user[email]" type="email" />
</div>
<div class="invalid-feedback">can't be blank, is too short (minimum is 5 characters)</div>
<div class="invalid-feedback" id="user_email_feedback">can't be blank, is too short (minimum is 5 characters)</div>
</div>
HTML
output = @builder.email_field(:email, wrapper_class: "none-margin")
Expand All @@ -530,8 +508,8 @@ class BootstrapFormGroupTest < ActionView::TestCase
<form accept-charset="UTF-8" action="/users" class="new_user" id="new_user" method="post">
<div class="none-margin">
<label class="form-label required" for="user_email">Email</label>
<input required="required" class="form-control is-invalid" id="user_email" name="user[email]" type="text" />
<div class="invalid-feedback">can't be blank, is too short (minimum is 5 characters)</div>
<input required="required" class="form-control is-invalid" id="user_email" aria-labelledby="user_email_feedback" name="user[email]" type="text" />
<div class="invalid-feedback" id="user_email_feedback">can't be blank, is too short (minimum is 5 characters)</div>
<small class="form-text text-muted">This is required</small>
</div>
</form>
Expand Down
Loading