Bind '.error' class to manually created haml wrapper - ruby-on-rails

I have next group of controls:
.control-group.string.required.user_name
= f.input_field :name, required: true, class: 'form-control'
= f.label 'User Name'
= f.error :name
Is there any way to bind '.control-group' to it's child input, so if input is invalid, wrapper will get class ".error" added?
Thanks

I've created a custom component for that, which looks as follows
config.wrappers :perfect_forms, tag: 'div', class: 'control-group', required: true, error_class: 'error' do |b|
b.use :html5
b.use :input, class: 'fotm-control', required: true
b.use :label
b.use :error, wrap_with: { tag: 'span', class: 'help-inline' }
end
Now there is a question, if it's possible to detect type of an input inside this config? Because currently to explicitly set a type of an input, I'm writing "input_html: { type: 'text'}" for needed input, but that would be awesome to handle this case inside a wrapper config. Like if type is 'email' - then insert type 'text'.

Related

Simple Form- control width of label and input (with bootstrap)

I am using Simple_form and Bootstrap.
I would like to use a horizontal wrapper, but I need to make the label wider and the input narrower. I would like to do this with bootstrap 4 vs custom css.
The label and input should be on the same line (inline), and right aligned.
col-md-8 for label and col-md-4 for input. How do I do that?
<%= f.input :role, :wrapper =>:horizontal_range, input_wrapper_html: { class: "col-md-4"}, label_wrapper_html: {class: "col-md-8"} %>
EDIT: I should add that the f.input :role is contained within a
<div class='row'>
<div class='col-md-6">
f.input :role
</div>
</div>
Second,
I need to add a % at the end of my input. However, it does not seem to work.
<%= f.input :pct_of_car , append: "%", :wrapper =>:horizontal_range %>
However, this does not seem to work. What is wrong with my syntax?
Third, how would one modify the vertical collection_inline to have 2 or 3 columns?
# vertical input for inline radio buttons and check boxes
config.wrappers :bs_vertical_collection_inline, item_wrapper_class: 'form-check form-check-inline', tag: 'fieldset', class: 'form-group', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
b.use :html5
b.optional :readonly
b.wrapper :legend_tag, tag: 'legend', class: 'col-form-label pt-0' do |ba|
ba.use :label_text
end
b.use :input, class: 'form-check-input', error_class: 'is-invalid', valid_class: 'is-valid'
b.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback d-block' }
b.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
end
Currently all the checkboxes are listed inline and have no structure. I need to list the choices in 2 or 3 columns so that they are easier to read. This is also a long list, so may need to wrap the choices in a scroll box.
You need to define your own custom wrapper or modify the default ones.
First, ensure you have the default wrappers in your repository.
Run rails g simple_form:install --bootstrap if you can not locate app/initializers/simple_form_bootstrap.rb.
Second, locate the Bootstrap grid classes in this initializer. For a horizontal form, they are found in a block that looks like this:
config.wrappers :horizontal_form, tag: 'div', class: 'form-group', error_class: 'has-error' do |b|
b.use :html5
b.use :placeholder
b.optional :maxlength
b.optional :minlength
b.optional :pattern
b.optional :min_max
b.optional :readonly
b.use :label, class: 'col-sm-3 control-label'
b.wrapper tag: 'div', class: 'col-sm-9' do |ba|
ba.use :input, class: 'form-control'
ba.use :error, wrap_with: { tag: 'span', class: 'help-block' }
ba.use :hint, wrap_with: { tag: 'p', class: 'help-block' }
end
end
Third, change the wrapper!
In this snippet, change col-sm-9 to col-sm-8.
Also Change col-sm-3 to col-sm-4.
Finishing up
Save. Restart your Rails server. Now all forms will have 33% width labels, and 66% width inputs.
If you don't want to apply this globally, pass the wrapper: :my_wrapper option to any input and create a new custom wrapper that does what you'd like it to do.
Gotta love SimpleForm!
To set class for input and label, please use input_html and label_html:
<%= f.input :role, :wrapper => :horizontal_range, input_html: { class: "col-md-4"}, label_html: {class: "col-md-8"} %>
Regarding the second issue - if you are not using hints, probably the easiest solution would be to do it like this:
<%= f.input :pct_of_car , hint: "%", :wrapper =>:horizontal_range %>
Then, you can style it by adding a custom class to the hint with hint_html option (similar to input_html and label_html).
Update
A better solution for adding custom text is to use block for the input:
<%= f.input(:role, :wrapper => :horizontal_range, label_html: {class: "col-md-8"}) do %>
<div class='col-md-4'>
<%= f.input(:role, components: [:input], :wrapper => false, label: false) %>
<span>%</span>
</div>
<% end %>
Thanks to that, your label has col-md-8 class, and input with your text are wrapped in a div with col-md-4 class.

Rails simple_form gem is adding a green border to inputs that are pre-populated

I am having a problem with the rails simple_form gem. I am using bootstrap 4 along with it.
I have installed the gem by adding gem 'simple_form' to the Gemfile. I have also run the generator via rails g simple_form:install --bootstrap.
Simple Form works almost perfectly in my app. Here is an example using a model called 'Store' that has one string attribute: 'name'.
<%= simple_form_for #store do |f| %>
<%= f.input :name %>
<%= f.button :submit, class: "btn-primary" %>
<%= link_to "Cancel", stores_url, class: %w[btn btn-danger] %>
<% end %>
The only problem I'm having with this code is that when the form is used for the update page, simple_form adds an '.is-valid' class to the input element which causes bootstrap to add a green border to the field. This does not happen when the field is not pre-filled such as when using the form for the 'new' action.
Thanks
In config/initializers/simple_form_bootstrap.rb you have a few different blocks that start with config.wrapper. You can remove any reference to valid_class: 'is-valid' from them so that it is no longer included in your form inputs. i.e....
Change this
config.wrappers :vertical_form, tag: 'div', class: 'form-group', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
...
b.use :input, class: 'form-control', error_class: 'is-invalid', valid_class: 'is-valid'
...
end
To this (by removing valid_class)
config.wrappers :vertical_form, tag: 'div', class: 'form-group', error_class: 'form-group-invalid' do |b|
...
b.use :input, class: 'form-control', error_class: 'is-invalid'
...
end
And you can remove references to error_class as well if you don't want that included.

How to remove default input class type from Simple Form, using Rails 4 and Bootstrap 4?

I'm using Rails 4.2.4 with Bootstrap 4 (using the bootstrap_ruby gem).
Simple Form adds input type classes to the form... if the input is a string it will add a class string to the input. I wanted to know how to stop this from happening?
For example, if I had a form with a file input.
simple_form_for #attachment do |f|
f.input_field :file, as: :file
end
It will produce the following HTML:
<form>
...
<div class="form-group file optional photo_image">
<label class="file optional control-label" for="attachment_file">File</label>
<input class="file optional" type="file" name="attachment[file]" id="attachment_file"></div>
...
</form>
It adds the file class to the label and input fields. Is there a way to remove the file class when the form is being built?
I'm trying to use Bootstrap 4 (Alpha) and it's clashing with the file class name.
I thought I could do it on the config.wrappers but it adds the type of input as a class eg. string, file.
Thanks in advance.
Bootstrap 4's naming choice on the custom file field is unfortunate, as it is very generic.
Unfortunately, there is no easy way to toggle that automatically added css-classes with SimpleForm.
My solution is to introduce a new input field which just inherits from the FileInput, so it receives a different name and so a different css-class:
// initializer
# create a new file_hack input type same as file
class SimpleForm::Inputs::FileHackInput < SimpleForm::Inputs::FileInput
end
# optional: map file_hack to a input type configuration for easier classes etc.
SimpleForm.setup do |config|
...
config.wrapper_mappings = {
# check_boxes: :vertical_radio_and_checkboxes,
# radio_buttons: :horizontal_radio_and_checkboxes,
# file: :vertical_file_input,
file_hack: :vertical_file_input,
# boolean: :vertical_boolean
}
config.wrappers :vertical_file_input, tag: 'fieldset', class: 'form-group', error_class: 'has-error' do |b|
b.use :html5
b.use :placeholder
b.use :label, class: 'control-label'
b.wrapper tag: 'div' do |ba|
ba.use :input, class: 'form-control-file'
ba.use :error, wrap_with: { tag: 'span', class: 'help-block' }
ba.use :hint, wrap_with: { tag: 'div', class: 'text-muted' }
end
end
Call the file field as the new input "type".
// form
= f.input :file, as: :file_hack

Simple_Form: Use fieldset/legend for radio buttons / checkboxes

From an accessibility point of view, it is very important to use fieldset/legend combinations for radio buttons and checkboxes:
fieldset
legend What is your sex?
label for="male" Male
input type="radio" id="male"
label for="female" Female
input type="radio" id="female"
This is even true when being inside a fieldset/legend pair already, like so:
fieldset
legend Personal information
label for="name"
input type="text" id="name"
fieldset // Yes, this is a fieldset inside a fieldset!
legend What is your sex?
label for="male" Male
input type="radio" id="male"
label for="female" Female
input type="radio" id="female"
label for="email"
input type="text" id="email"
Simple_Form automatically generates label elements for these legends, though. Is there an easy way to tell Simple_Form to create fieldset/legends, or do I have to work around this with custom wrappers?
Update
For a first work around, I created a custom wrapper like so:
config.wrappers :vertical_radio_and_checkboxes, tag: 'fieldset', class: 'form-group', error_class: 'has-error' do |b|
b.use :html5
b.optional :readonly
b.wrapper tag: 'legend', class: 'col-sm-3 control-label' do |ba|
ba.use :label # TODO: Doesn't need to be a label tag, see http://stackoverflow.com/questions/29261556/simple-form-use-fieldset-legend-for-radio-buttons-checkboxes
end
b.wrapper tag: 'div', class: 'col-sm-9' do |ba|
ba.use :input
ba.use :error, wrap_with: { tag: 'span', class: 'help-block' }
ba.use :hint, wrap_with: { tag: 'p', class: 'help-block' }
end
end
This is okay for the time being, although I didn't find a way to tell Simple_Form not to generate a label element for the label (which doesn't point to any ID, which implies that it can't be a correct usage anyway, but it has some important CSS classes added to it, so I didn't want to just abandon it and use label_text).
I have added an issue to the Simple_Form-Bootstrap repo: fieldset/legend should be used for multiple checkboxes/radiobuttons.
To prevent the simple_form generated <label> you can use :label => false
for example in your _form.haml:
= f.input :name, :label => false
in your form.
Is that what you want to achieve? Not sure that's is all behind your question.
just in case, there might be some useful info here

Rails 3 + SimpleForm + Client side validations + bootstrap: adding error wrapper for whole control group

I have a form with control group that has multiple input fields, that are displayed in-line. One of these fields has error validations. Unfortunately it is in the middle of the control group and for some crazy design reasons (not my call) I cannot move it to the far right of the group. So I would like the error messages to be appended to the whole control group, not the individual input fields, like it is by default. So my questions are:
1) Is it possible to do in the easy, non-intrusive way eg. only changing configuration files? I tried to meddle with:
config/initializers/simple_form_bootstrap.rb
but the best I could do was:
config.wrappers :none, :tag => false do |b|
b.use :html5
b.use :placeholder
b.use :label
b.use :input
end
config.wrapper_mappings = { some_input: :none }
and it's almost working, except the error message disappears after I click submit. Other attempts resulted in form not being displayed at all.
2) How can I change the behavior of Simple Form and/or Client Side Validations in a way that I explicitly say which div I want my error message to be displayed? I am aware that this contradicts the idea of errors being shown somewhere around the bad input field, but I really don't want to write custom validation just for this one form.
I think you should reinstall bootstrap and simple form.
you can try this command:
rails generate simple_form:install --bootstrap
or you can refer to my wrapper config
config.wrappers :bootstrap, tag: 'div', class: 'control-group', error_class: 'error' do |b|
b.use :html5
b.use :placeholder
b.use :label
b.wrapper tag: 'div', class: 'controls' do |ba|
ba.use :input, class: 'form-control'
ba.use :error, wrap_with: { tag: 'span', class: 'help-inline' }
ba.use :hint, wrap_with: { tag: 'p', class: 'help-block' }
end end
default wrapper: config.default_wrapper = :bootstrap
check attributes in your css files

Resources