Skip to content

Commit

Permalink
Add support for date/time/datetime_select fields
Browse files Browse the repository at this point in the history
  • Loading branch information
MichalRemis authored and tagliala committed Apr 26, 2020
1 parent c7468a6 commit 5fa9a94
Show file tree
Hide file tree
Showing 10 changed files with 279 additions and 2 deletions.
2 changes: 2 additions & 0 deletions dist/client-side-validations.esm.js
Original file line number Diff line number Diff line change
Expand Up @@ -626,6 +626,8 @@ var cleanNestedElementName = function cleanNestedElementName(elementName, nested

var cleanElementName = function cleanElementName(elementName, validators) {
elementName = elementName.replace(/\[(\w+_attributes)\]\[[\da-z_]+\](?=\[(?:\w+_attributes)\])/g, '[$1][]');
elementName = elementName.replace(/\(\di\)/g, ''); // date/time_select (1/2/3/4/5i) fields

var nestedMatches = elementName.match(/\[(\w+_attributes)\].*\[(\w+)\]$/);

if (nestedMatches) {
Expand Down
2 changes: 2 additions & 0 deletions dist/client-side-validations.js
Original file line number Diff line number Diff line change
Expand Up @@ -632,6 +632,8 @@

var cleanElementName = function cleanElementName(elementName, validators) {
elementName = elementName.replace(/\[(\w+_attributes)\]\[[\da-z_]+\](?=\[(?:\w+_attributes)\])/g, '[$1][]');
elementName = elementName.replace(/\(\di\)/g, ''); // date/time_select (1/2/3/4/5i) fields

var nestedMatches = elementName.match(/\[(\w+_attributes)\].*\[(\w+)\]$/);

if (nestedMatches) {
Expand Down
9 changes: 9 additions & 0 deletions lib/client_side_validations/action_view/form_builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,15 @@ def collection_select(method, collection, value_method, text_method, options = {
super(method, collection, value_method, text_method, options, html_options)
end

%i[date_select datetime_select time_select].each do |method_name|
define_method method_name do |method, options = {}, html_options = {}|
build_validation_options(method, options)
html_options.delete(:validate)

super(method, options, html_options)
end
end

def fields_for(record_name, record_object = nil, fields_options = {}, &block)
if record_object.is_a?(Hash) && record_object.extractable_options?
fields_options = record_object
Expand Down
1 change: 1 addition & 0 deletions src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ const cleanNestedElementName = (elementName, nestedMatches, validators) => {

const cleanElementName = (elementName, validators) => {
elementName = elementName.replace(/\[(\w+_attributes)\]\[[\da-z_]+\](?=\[(?:\w+_attributes)\])/g, '[$1][]')
elementName = elementName.replace(/\(\di\)/g, '') // date/time_select (1/2/3/4/5i) fields

const nestedMatches = elementName.match(/\[(\w+_attributes)\].*\[(\w+)\]$/)

Expand Down
36 changes: 36 additions & 0 deletions test/action_view/cases/test_form_for_helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,42 @@ def test_time_zone_select_with_validate_options
assert_dom_equal expected, output_buffer
end

def test_date_select
form_for(@post, validate: true) do |f|
concat f.date_select(:cost)
end

validators = { 'post[cost]' => { presence: [{ message: "can't be blank" }] } }
expected = whole_form_for('/posts', 'new_post', 'new_post', validators: validators) do
date_select :post, :cost
end
assert_dom_equal expected, output_buffer
end

def test_datetime_select
form_for(@post, validate: true) do |f|
concat f.datetime_select(:cost)
end

validators = { 'post[cost]' => { presence: [{ message: "can't be blank" }] } }
expected = whole_form_for('/posts', 'new_post', 'new_post', validators: validators) do
datetime_select :post, :cost
end
assert_dom_equal expected, output_buffer
end

def test_time_select
form_for(@post, validate: true) do |f|
concat f.time_select(:cost)
end

validators = { 'post[cost]' => { presence: [{ message: "can't be blank" }] } }
expected = whole_form_for('/posts', 'new_post', 'new_post', validators: validators) do
time_select :post, :cost
end
assert_dom_equal expected, output_buffer
end

def test_as_form_option_with_new_record_rails
form_for(@post, as: :article, validate: true) do
concat content_tag(:span, 'Dummy Content')
Expand Down
37 changes: 37 additions & 0 deletions test/action_view/cases/test_form_with_helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,43 @@ def test_form_with_time_zone_select_with_validate_options
assert_dom_equal expected, output_buffer
end

def test_form_with_date_select
form_with(model: @post, validate: true) do |f|
concat f.date_select(:cost)
end

validators = { 'post[cost]' => { presence: [{ message: "can't be blank" }] } }
expected = whole_form_with('/posts', validators: validators) do
date_select :post, :cost
end
assert_dom_equal expected, output_buffer
end

def test_form_with_datetime_select
form_with(model: @post, validate: true) do |f|
concat f.datetime_select(:cost)
end

validators = { 'post[cost]' => { presence: [{ message: "can't be blank" }] } }
expected = whole_form_with('/posts', validators: validators) do
datetime_select :post, :cost
end
assert_dom_equal expected, output_buffer
end

def test_form_with_time_select
form_with(model: @post, validate: true) do |f|
concat f.time_select(:cost)
end

validators = { 'post[cost]' => { presence: [{ message: "can't be blank" }] } }
expected = whole_form_with('/posts', validators: validators) do
time_select :post, :cost
end

assert_dom_equal expected, output_buffer
end

def test_form_with_as_form_option_with_new_record_rails
form_with(model: @post, as: :article, validate: true) do
concat content_tag(:span, 'Dummy Content')
Expand Down
33 changes: 33 additions & 0 deletions test/action_view/cases/test_legacy_form_for_helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,39 @@ def test_file_field
assert_dom_equal expected, output_buffer
end

def test_date_select
form_for(@post) do |f|
concat f.date_select(:cost)
end

expected = whole_form_for('/posts', 'new_post', 'new_post') do
date_select :post, :cost
end
assert_dom_equal expected, output_buffer
end

def test_datetime_select
form_for(@post) do |f|
concat f.datetime_select(:cost)
end

expected = whole_form_for('/posts', 'new_post', 'new_post') do
datetime_select :post, :cost
end
assert_dom_equal expected, output_buffer
end

def test_time_select
form_for(@post) do |f|
concat f.time_select(:cost)
end

expected = whole_form_for('/posts', 'new_post', 'new_post') do
time_select :post, :cost
end
assert_dom_equal expected, output_buffer
end

def test_check_box
form_for(@post) do |f|
concat f.check_box(:cost)
Expand Down
34 changes: 34 additions & 0 deletions test/action_view/cases/test_legacy_form_with_helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,40 @@ def test_form_with_file_field
assert_dom_equal expected, output_buffer
end

def test_form_with_date_select
form_with(model: @post) do |f|
concat f.date_select(:cost)
end

expected = whole_form_with('/posts') do
date_select :post, :cost
end
assert_dom_equal expected, output_buffer
end

def test_form_with_datetime_select
form_with(model: @post) do |f|
concat f.datetime_select(:cost)
end

expected = whole_form_with('/posts') do
datetime_select :post, :cost
end
assert_dom_equal expected, output_buffer
end

def test_form_with_time_select
form_with(model: @post) do |f|
concat f.time_select(:cost)
end

expected = whole_form_with('/posts') do
time_select :post, :cost
end

assert_dom_equal expected, output_buffer
end

def test_form_with_check_box
form_with(model: @post) do |f|
concat f.check_box(:cost)
Expand Down
125 changes: 123 additions & 2 deletions test/javascript/public/test/validateElement.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ QUnit.module('Validate Element', {
'user[phone_numbers_attributes][deeply][nested][][attribute]': { presence: [{ message: 'must be present' }] },
'user[phone_numbers_attributes][][labels_attributes][][label]': { presence: [{ message: 'must be present' }] },
'user[a_attributes][][b_attributes][][c_attributes][][d_attributes][][e]': { presence: [{ message: 'must be present' }] },
customized_field: { length: [{ messages: { minimum: 'is too short (minimum is 4 characters)' }, minimum: 4 }] }
customized_field: { length: [{ messages: { minimum: 'is too short (minimum is 4 characters)' }, minimum: 4 }] },
'user[date_of_sign_up]': { presence: [{ message: 'must be present' }] },
'user[date_of_birth]': { presence: [{ message: 'must be present' }] },
'user[time_of_birth]': { presence: [{ message: 'must be present' }] },
}
}

Expand Down Expand Up @@ -132,7 +135,73 @@ QUnit.module('Validate Element', {
id: 'customized_field',
type: 'text'
}))

.append($('<label for="user_date_of_sign_up">Date Field</label>'))
.append($('<input />', {
name: 'user[date_of_sign_up]',
id: 'user_date_of_sign_up',
type: 'date'
}))
.append($('<label for="user_time_of_birth_1i">Time select</label>'))
.append($('<input />', {
type: 'hidden',
id: 'user_time_of_birth_1i',
name: 'user[time_of_birth(1i)]',
value: 1
}))
.append($('<input />', {
type: 'hidden',
id: 'user_time_of_birth_2i',
name: 'user[time_of_birth(2i)]',
value: 1
}))
.append($('<input />', {
type: 'hidden',
id: 'user_time_of_birth_3i',
name: 'user[time_of_birth(3i)]',
value: 1
}))
.append($('<select>', {
id: 'user_time_of_birth_4i',
name: 'user[time_of_birth(4i)]',
})
.append($('<option value=""></option>'))
.append($('<option value="00">00</option>'))
.append($('<option value="01">01</option>'))
)
.append(':')
.append($('<select>', {
id: 'user_time_of_birth_5i',
name: 'user[time_of_birth(5i)]',
})
.append($('<option value=""></option>'))
.append($('<option value="00">00</option>'))
.append($('<option value="59">59</option>'))
)
.append($('<label for="user_date_of_birth_1i">Date select</label>'))
.append($('<select>', {
id: 'user_date_of_birth_1i',
name: 'user[time_of_birth(1i)]',
})
.append($('<option value=""></option>'))
.append($('<option value="2015">2015</option>'))
.append($('<option value="2016">2016</option>'))
)
.append($('<select>', {
id: 'user_date_of_birth_2i',
name: 'user[time_of_birth(2i)]',
})
.append($('<option value=""></option>'))
.append($('<option value="1">January</option>'))
.append($('<option value="2">February</option>'))
)
.append($('<select>', {
id: 'user_date_of_birth_3i',
name: 'user[time_of_birth(3i)]',
})
.append($('<option value=""></option>'))
.append($('<option value="1">2</option>'))
.append($('<option value="2">2</option>'))
)
$('form#new_user').validate()
},

Expand All @@ -152,6 +221,58 @@ QUnit.test('Validate when focusouting on customized_field', function (assert) {
assert.ok(label.parent().hasClass('field_with_errors'))
})

QUnit.test('Validate when focusouting on date_field', function (assert) {
var form = $('form#new_user')
var input = form.find('input#user_date_of_sign_up')
var label = $('label[for="user_date_of_sign_up"]')

input.trigger('focusout')
assert.ok(input.parent().hasClass('field_with_errors'))
assert.ok(label.parent().hasClass('field_with_errors'))
})

QUnit.test('Validate validations of date_select', function (assert) {
var form = $('form#new_user')

//var label = $('label[for="user_date_of_birth_1i"]')
var input_year = form.find('select#user_date_of_birth_1i')
var input_month = form.find('select#user_date_of_birth_2i')
var input_day = form.find('select#user_date_of_birth_3i')

input_year.trigger('focusout')
assert.ok(input_year.parent().hasClass('field_with_errors'))

input_month.trigger('focusout')
assert.ok(input_month.parent().hasClass('field_with_errors'))

input_day.trigger('focusout')
assert.ok(input_day.parent().hasClass('field_with_errors'))

// showing validation messages doesnt work well with this.
// JS Formbuilder must be customized for these types of fields
// to share error message and hide error only when all 3 selects are valid

})

QUnit.test('Validate validations of time_select', function (assert) {
var form = $('form#new_user')

//var label = $('label[for="user_time_of_birth_4i"]')
var input_hour = form.find('select#user_time_of_birth_4i')
var input_minute = form.find('select#user_time_of_birth_5i')

input_hour.trigger('focusout')
assert.ok(input_hour.parent().hasClass('field_with_errors'))

input_minute.trigger('focusout')
assert.ok(input_minute.parent().hasClass('field_with_errors'))

// showing validation messages doesnt work well with this.
// JS Formbuilder must be customized for these types of fields
// to share error message and hide error only when all 3 selects are valid
})


QUnit.test('Validate when focusouting', function (assert) {
var form = $('form#new_user')
var input = form.find('input#user_name')
Expand Down
2 changes: 2 additions & 0 deletions vendor/assets/javascripts/rails.validations.js
Original file line number Diff line number Diff line change
Expand Up @@ -632,6 +632,8 @@

var cleanElementName = function cleanElementName(elementName, validators) {
elementName = elementName.replace(/\[(\w+_attributes)\]\[[\da-z_]+\](?=\[(?:\w+_attributes)\])/g, '[$1][]');
elementName = elementName.replace(/\(\di\)/g, ''); // date/time_select (1/2/3/4/5i) fields

var nestedMatches = elementName.match(/\[(\w+_attributes)\].*\[(\w+)\]$/);

if (nestedMatches) {
Expand Down

0 comments on commit 5fa9a94

Please sign in to comment.