Skip to content

Use field specific wrappers #81

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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
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
7 changes: 5 additions & 2 deletions dist/simple-form.bootstrap4.esm.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,17 @@ import ClientSideValidations from '@client-side-validations/client-side-validati

ClientSideValidations.formBuilders['SimpleForm::FormBuilder'] = {
add: function add(element, settings, message) {
this.wrapper(settings.wrapper).add.call(this, element, settings, message);
this.wrapper(this.wrapperName(element, settings)).add.call(this, element, settings, message);
},
remove: function remove(element, settings) {
this.wrapper(settings.wrapper).remove.call(this, element, settings);
this.wrapper(this.wrapperName(element, settings)).remove.call(this, element, settings);
},
wrapper: function wrapper(name) {
return this.wrappers[name] || this.wrappers["default"];
},
wrapperName: function wrapperName(element, settings) {
return element.data('clientSideValidationsWrapper') || settings.wrapper;
},
wrappers: {
"default": {
add: function add(element, settings, message) {
Expand Down
7 changes: 5 additions & 2 deletions dist/simple-form.bootstrap4.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,17 @@

ClientSideValidations.formBuilders['SimpleForm::FormBuilder'] = {
add: function add(element, settings, message) {
this.wrapper(settings.wrapper).add.call(this, element, settings, message);
this.wrapper(this.wrapperName(element, settings)).add.call(this, element, settings, message);
},
remove: function remove(element, settings) {
this.wrapper(settings.wrapper).remove.call(this, element, settings);
this.wrapper(this.wrapperName(element, settings)).remove.call(this, element, settings);
},
wrapper: function wrapper(name) {
return this.wrappers[name] || this.wrappers["default"];
},
wrapperName: function wrapperName(element, settings) {
return element.data('clientSideValidationsWrapper') || settings.wrapper;
},
wrappers: {
"default": {
add: function add(element, settings, message) {
Expand Down
7 changes: 5 additions & 2 deletions dist/simple-form.esm.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,17 @@ import ClientSideValidations from '@client-side-validations/client-side-validati

ClientSideValidations.formBuilders['SimpleForm::FormBuilder'] = {
add: function add(element, settings, message) {
this.wrapper(settings.wrapper).add.call(this, element, settings, message);
this.wrapper(this.wrapperName(element, settings)).add.call(this, element, settings, message);
},
remove: function remove(element, settings) {
this.wrapper(settings.wrapper).remove.call(this, element, settings);
this.wrapper(this.wrapperName(element, settings)).remove.call(this, element, settings);
},
wrapper: function wrapper(name) {
return this.wrappers[name] || this.wrappers["default"];
},
wrapperName: function wrapperName(element, settings) {
return element.data('clientSideValidationsWrapper') || settings.wrapper;
},
wrappers: {
"default": {
add: function add(element, settings, message) {
Expand Down
7 changes: 5 additions & 2 deletions dist/simple-form.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,17 @@

ClientSideValidations.formBuilders['SimpleForm::FormBuilder'] = {
add: function add(element, settings, message) {
this.wrapper(settings.wrapper).add.call(this, element, settings, message);
this.wrapper(this.wrapperName(element, settings)).add.call(this, element, settings, message);
},
remove: function remove(element, settings) {
this.wrapper(settings.wrapper).remove.call(this, element, settings);
this.wrapper(this.wrapperName(element, settings)).remove.call(this, element, settings);
},
wrapper: function wrapper(name) {
return this.wrappers[name] || this.wrappers["default"];
},
wrapperName: function wrapperName(element, settings) {
return element.data('clientSideValidationsWrapper') || settings.wrapper;
},
wrappers: {
"default": {
add: function add(element, settings, message) {
Expand Down
10 changes: 10 additions & 0 deletions lib/client_side_validations/simple_form/form_builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ def input(attribute_name, options = {}, &block)
options.delete(:validate)
end

add_field_specific_wrapper_name_to_field_options(attribute_name, options, &block)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moving this to the parent gem will not be straightforward. I think I should add the method call to all the overrides

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I agree


super(attribute_name, options, &block)
end

Expand All @@ -34,6 +36,14 @@ def wrapper_error_component
wrapper.find(:full_error)
end
end

def add_field_specific_wrapper_name_to_field_options(attribute_name, options, &block)
wrapper_name = options[:wrapper] || find_wrapper_mapping(find_input(attribute_name, options, &block).input_type)
return if wrapper_name.nil?

options[:input_html] ||= {}
options[:input_html][:'data-client-side-validations-wrapper'] = wrapper_name
end
end
end
end
Expand Down
9 changes: 6 additions & 3 deletions src/main.bootstrap4.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,23 @@ import ClientSideValidations from '@client-side-validations/client-side-validati

ClientSideValidations.formBuilders['SimpleForm::FormBuilder'] = {
add: function (element, settings, message) {
this.wrapper(settings.wrapper).add.call(this, element, settings, message)
this.wrapper(this.wrapperName(element, settings)).add.call(this, element, settings, message)
},
remove: function (element, settings) {
this.wrapper(settings.wrapper).remove.call(this, element, settings)
this.wrapper(this.wrapperName(element, settings)).remove.call(this, element, settings)
},
wrapper: function (name) {
return this.wrappers[name] || this.wrappers.default
},
wrapperName: function (element, settings) {
return element.data('clientSideValidationsWrapper') || settings.wrapper
},

wrappers: {
default: {
add (element, settings, message) {
const wrapperElement = element.parent()
let errorElement = wrapperElement.find(settings.error_tag + '.invalid-feedback')
var errorElement = wrapperElement.find(settings.error_tag + '.invalid-feedback')

if (!errorElement.length) {
errorElement = $('<' + settings.error_tag + '>', { class: 'invalid-feedback', text: message })
Expand Down
9 changes: 6 additions & 3 deletions src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,23 @@ import ClientSideValidations from '@client-side-validations/client-side-validati

ClientSideValidations.formBuilders['SimpleForm::FormBuilder'] = {
add: function (element, settings, message) {
this.wrapper(settings.wrapper).add.call(this, element, settings, message)
this.wrapper(this.wrapperName(element, settings)).add.call(this, element, settings, message)
},
remove: function (element, settings) {
this.wrapper(settings.wrapper).remove.call(this, element, settings)
this.wrapper(this.wrapperName(element, settings)).remove.call(this, element, settings)
},
wrapper: function (name) {
return this.wrappers[name] || this.wrappers.default
},
wrapperName: function (element, settings) {
return element.data('clientSideValidationsWrapper') || settings.wrapper
},

wrappers: {
default: {
add (element, settings, message) {
const wrapper = element.closest(settings.wrapper_tag + '.' + settings.wrapper_class.replace(/ /g, '.'))
let errorElement = wrapper.find(settings.error_tag + '.' + settings.error_class.replace(/ /g, '.'))
var errorElement = wrapper.find(settings.error_tag + '.' + settings.error_class.replace(/ /g, '.'))

if (!errorElement.length) {
errorElement = $('<' + settings.error_tag + '>', { class: settings.error_class, text: message })
Expand Down
28 changes: 27 additions & 1 deletion test/javascript/public/test/form_builders/validateSimpleForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ QUnit.module('Validate SimpleForm', {
wrapper: 'default'
},
validators: {
'user[name]': { presence: [{ message: 'must be present' }], format: [{ message: 'is invalid', 'with': { options: 'g', source: '\\d+' } }] }
'user[name]': { presence: [{ message: 'must be present' }], format: [{ message: 'is invalid', 'with': { options: 'g', source: '\\d+' } }] },
'user[date_of_birth]': { presence: [{ message: 'must be present' }] }
}
}

Expand All @@ -40,6 +41,12 @@ QUnit.module('Validate SimpleForm', {
type: 'text'
}))
.append($('<label for="user_name">Name</label>'))
.append($('<input />', {
name: 'user[date_of_birth]',
id: 'date_of_birth',
type: 'text',
'data-client-side-validations-wrapper': 'custom_date_wrapper'
}))
$('form#new_user').validate()
}
})
Expand Down Expand Up @@ -82,3 +89,22 @@ QUnit.test('Validate pre-existing error blocks are re-used', function (assert) {
assert.ok(input.parent().find('span.error:contains("is invalid")').length === 1)
assert.ok(form.find('span.error').length === 1)
})

QUnit.test('Validate correct JS Builder\'s wrapper is called for custom_wrapper', function (assert) {
const oldWrappers = $.extend({}, ClientSideValidations.formBuilders['SimpleForm::FormBuilder'].wrappers)

// It would be probably better to use some stub library but I want to keep it simple
let customWrapperCalled = false;

ClientSideValidations.formBuilders['SimpleForm::FormBuilder'].wrappers['custom_date_wrapper'] = {
add: function(element, settings, message) { customWrapperCalled=true; },
remove: function(element, settings) {}
}

var form = $('form#new_user');
var input = form.find('input#date_of_birth')
input.trigger('focusout')

assert.ok(customWrapperCalled);
ClientSideValidations.formBuilders['SimpleForm::FormBuilder'].wrappers = oldWrappers
})
24 changes: 24 additions & 0 deletions test/simple_form/cases/test_form_helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,30 @@ def test_input_override

assert_dom_equal expected, output_buffer
end

def test_input_override_with_custom_wrapper_name
simple_form_for(@post, validate: true, wrapper: :default) do |f|
concat f.input(:cost, validate: false, wrapper: :custom_date_wrapper)
end

csv_data = {
html_settings: {
type: 'SimpleForm::FormBuilder',
error_class: 'error',
error_tag: 'span',
wrapper_error_class: 'field_with_errors',
wrapper_tag: 'div',
wrapper_class: 'input',
wrapper: 'default'
},
number_format: { separator: '.', delimiter: ',' },
validators: {}
}

expected = %(<form accept-charset="UTF-8" action="/posts" class="simple_form new_post" data-client-side-validations="#{CGI.escapeHTML(csv_data.to_json)}" id="new_post" method="post" novalidate="novalidate"><input name="utf8" type="hidden" value="&#x2713;" /><div class="string required post_cost"><input class="form-control string required" data-client-side-validations-wrapper="custom_date_wrapper" type="text" name="post[cost]" id="post_cost" /></div></form>)

assert_dom_equal expected, output_buffer
end
end
end
end
5 changes: 4 additions & 1 deletion test/test_loader.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@
require 'base_helper'
require 'client_side_validations/simple_form'

SimpleForm.setup do
SimpleForm.setup do |config|
config.wrappers :custom_date_wrapper, tag: 'div' do |b|
b.use :input, class: 'form-control'
end
end

TestApp::Application.initialize!
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,17 @@

ClientSideValidations.formBuilders['SimpleForm::FormBuilder'] = {
add: function add(element, settings, message) {
this.wrapper(settings.wrapper).add.call(this, element, settings, message);
this.wrapper(this.wrapperName(element, settings)).add.call(this, element, settings, message);
},
remove: function remove(element, settings) {
this.wrapper(settings.wrapper).remove.call(this, element, settings);
this.wrapper(this.wrapperName(element, settings)).remove.call(this, element, settings);
},
wrapper: function wrapper(name) {
return this.wrappers[name] || this.wrappers["default"];
},
wrapperName: function wrapperName(element, settings) {
return element.data('clientSideValidationsWrapper') || settings.wrapper;
},
wrappers: {
"default": {
add: function add(element, settings, message) {
Expand Down
7 changes: 5 additions & 2 deletions vendor/assets/javascripts/rails.validations.simple_form.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,17 @@

ClientSideValidations.formBuilders['SimpleForm::FormBuilder'] = {
add: function add(element, settings, message) {
this.wrapper(settings.wrapper).add.call(this, element, settings, message);
this.wrapper(this.wrapperName(element, settings)).add.call(this, element, settings, message);
},
remove: function remove(element, settings) {
this.wrapper(settings.wrapper).remove.call(this, element, settings);
this.wrapper(this.wrapperName(element, settings)).remove.call(this, element, settings);
},
wrapper: function wrapper(name) {
return this.wrappers[name] || this.wrappers["default"];
},
wrapperName: function wrapperName(element, settings) {
return element.data('clientSideValidationsWrapper') || settings.wrapper;
},
wrappers: {
"default": {
add: function add(element, settings, message) {
Expand Down