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

Add support for date/time/date_time selects #784

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
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
Comment on lines +251 to +253
Copy link
Contributor

@tagliala tagliala Apr 28, 2020

Choose a reason for hiding this comment

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

This will require attention. More details in the main PR

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I know. But I am focused on getting CSV-simple_form work. Not sure if I will have time for this here. I just put it into main, because it was missing here and believed it won't break anything (because time/date_selects wasn't working before anyway)


})

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