Skip to content

Commit 06ce081

Browse files
MichalRemistagliala
authored andcommitted
Add support for date/time/datetime_select fields
1 parent a49dd74 commit 06ce081

File tree

10 files changed

+279
-2
lines changed

10 files changed

+279
-2
lines changed

dist/client-side-validations.esm.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -626,6 +626,8 @@ var cleanNestedElementName = function cleanNestedElementName(elementName, nested
626626

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

631633
if (nestedMatches) {

dist/client-side-validations.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -632,6 +632,8 @@
632632

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

637639
if (nestedMatches) {

lib/client_side_validations/action_view/form_builder.rb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,15 @@ def collection_select(method, collection, value_method, text_method, options = {
6262
super(method, collection, value_method, text_method, options, html_options)
6363
end
6464

65+
%i[date_select datetime_select time_select].each do |method_name|
66+
define_method method_name do |method, options = {}, html_options = {}|
67+
build_validation_options(method, options)
68+
html_options.delete(:validate)
69+
70+
super(method, options, html_options)
71+
end
72+
end
73+
6574
def fields_for(record_name, record_object = nil, fields_options = {}, &block)
6675
if record_object.is_a?(Hash) && record_object.extractable_options?
6776
fields_options = record_object

src/main.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ const cleanNestedElementName = (elementName, nestedMatches, validators) => {
8282

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

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

test/action_view/cases/test_form_for_helpers.rb

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -432,6 +432,42 @@ def test_time_zone_select_with_validate_options
432432
assert_dom_equal expected, output_buffer
433433
end
434434

435+
def test_date_select
436+
form_for(@post, validate: true) do |f|
437+
concat f.date_select(:cost)
438+
end
439+
440+
validators = { 'post[cost]' => { presence: [{ message: "can't be blank" }] } }
441+
expected = whole_form_for('/posts', 'new_post', 'new_post', validators: validators) do
442+
date_select :post, :cost
443+
end
444+
assert_dom_equal expected, output_buffer
445+
end
446+
447+
def test_datetime_select
448+
form_for(@post, validate: true) do |f|
449+
concat f.datetime_select(:cost)
450+
end
451+
452+
validators = { 'post[cost]' => { presence: [{ message: "can't be blank" }] } }
453+
expected = whole_form_for('/posts', 'new_post', 'new_post', validators: validators) do
454+
datetime_select :post, :cost
455+
end
456+
assert_dom_equal expected, output_buffer
457+
end
458+
459+
def test_time_select
460+
form_for(@post, validate: true) do |f|
461+
concat f.time_select(:cost)
462+
end
463+
464+
validators = { 'post[cost]' => { presence: [{ message: "can't be blank" }] } }
465+
expected = whole_form_for('/posts', 'new_post', 'new_post', validators: validators) do
466+
time_select :post, :cost
467+
end
468+
assert_dom_equal expected, output_buffer
469+
end
470+
435471
def test_as_form_option_with_new_record_rails
436472
form_for(@post, as: :article, validate: true) do
437473
concat content_tag(:span, 'Dummy Content')

test/action_view/cases/test_form_with_helpers.rb

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,43 @@ def test_form_with_time_zone_select_with_validate_options
462462
assert_dom_equal expected, output_buffer
463463
end
464464

465+
def test_form_with_date_select
466+
form_with(model: @post, validate: true) do |f|
467+
concat f.date_select(:cost)
468+
end
469+
470+
validators = { 'post[cost]' => { presence: [{ message: "can't be blank" }] } }
471+
expected = whole_form_with('/posts', validators: validators) do
472+
date_select :post, :cost
473+
end
474+
assert_dom_equal expected, output_buffer
475+
end
476+
477+
def test_form_with_datetime_select
478+
form_with(model: @post, validate: true) do |f|
479+
concat f.datetime_select(:cost)
480+
end
481+
482+
validators = { 'post[cost]' => { presence: [{ message: "can't be blank" }] } }
483+
expected = whole_form_with('/posts', validators: validators) do
484+
datetime_select :post, :cost
485+
end
486+
assert_dom_equal expected, output_buffer
487+
end
488+
489+
def test_form_with_time_select
490+
form_with(model: @post, validate: true) do |f|
491+
concat f.time_select(:cost)
492+
end
493+
494+
validators = { 'post[cost]' => { presence: [{ message: "can't be blank" }] } }
495+
expected = whole_form_with('/posts', validators: validators) do
496+
time_select :post, :cost
497+
end
498+
499+
assert_dom_equal expected, output_buffer
500+
end
501+
465502
def test_form_with_as_form_option_with_new_record_rails
466503
form_with(model: @post, as: :article, validate: true) do
467504
concat content_tag(:span, 'Dummy Content')

test/action_view/cases/test_legacy_form_for_helpers.rb

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,39 @@ def test_file_field
4141
assert_dom_equal expected, output_buffer
4242
end
4343

44+
def test_date_select
45+
form_for(@post) do |f|
46+
concat f.date_select(:cost)
47+
end
48+
49+
expected = whole_form_for('/posts', 'new_post', 'new_post') do
50+
date_select :post, :cost
51+
end
52+
assert_dom_equal expected, output_buffer
53+
end
54+
55+
def test_datetime_select
56+
form_for(@post) do |f|
57+
concat f.datetime_select(:cost)
58+
end
59+
60+
expected = whole_form_for('/posts', 'new_post', 'new_post') do
61+
datetime_select :post, :cost
62+
end
63+
assert_dom_equal expected, output_buffer
64+
end
65+
66+
def test_time_select
67+
form_for(@post) do |f|
68+
concat f.time_select(:cost)
69+
end
70+
71+
expected = whole_form_for('/posts', 'new_post', 'new_post') do
72+
time_select :post, :cost
73+
end
74+
assert_dom_equal expected, output_buffer
75+
end
76+
4477
def test_check_box
4578
form_for(@post) do |f|
4679
concat f.check_box(:cost)

test/action_view/cases/test_legacy_form_with_helpers.rb

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,40 @@ def test_form_with_file_field
4646
assert_dom_equal expected, output_buffer
4747
end
4848

49+
def test_form_with_date_select
50+
form_with(model: @post) do |f|
51+
concat f.date_select(:cost)
52+
end
53+
54+
expected = whole_form_with('/posts') do
55+
date_select :post, :cost
56+
end
57+
assert_dom_equal expected, output_buffer
58+
end
59+
60+
def test_form_with_datetime_select
61+
form_with(model: @post) do |f|
62+
concat f.datetime_select(:cost)
63+
end
64+
65+
expected = whole_form_with('/posts') do
66+
datetime_select :post, :cost
67+
end
68+
assert_dom_equal expected, output_buffer
69+
end
70+
71+
def test_form_with_time_select
72+
form_with(model: @post) do |f|
73+
concat f.time_select(:cost)
74+
end
75+
76+
expected = whole_form_with('/posts') do
77+
time_select :post, :cost
78+
end
79+
80+
assert_dom_equal expected, output_buffer
81+
end
82+
4983
def test_form_with_check_box
5084
form_with(model: @post) do |f|
5185
concat f.check_box(:cost)

test/javascript/public/test/validateElement.js

Lines changed: 123 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,10 @@ QUnit.module('Validate Element', {
1818
'user[phone_numbers_attributes][deeply][nested][][attribute]': { presence: [{ message: 'must be present' }] },
1919
'user[phone_numbers_attributes][][labels_attributes][][label]': { presence: [{ message: 'must be present' }] },
2020
'user[a_attributes][][b_attributes][][c_attributes][][d_attributes][][e]': { presence: [{ message: 'must be present' }] },
21-
customized_field: { length: [{ messages: { minimum: 'is too short (minimum is 4 characters)' }, minimum: 4 }] }
21+
customized_field: { length: [{ messages: { minimum: 'is too short (minimum is 4 characters)' }, minimum: 4 }] },
22+
'user[date_of_sign_up]': { presence: [{ message: 'must be present' }] },
23+
'user[date_of_birth]': { presence: [{ message: 'must be present' }] },
24+
'user[time_of_birth]': { presence: [{ message: 'must be present' }] },
2225
}
2326
}
2427

@@ -132,7 +135,73 @@ QUnit.module('Validate Element', {
132135
id: 'customized_field',
133136
type: 'text'
134137
}))
135-
138+
.append($('<label for="user_date_of_sign_up">Date Field</label>'))
139+
.append($('<input />', {
140+
name: 'user[date_of_sign_up]',
141+
id: 'user_date_of_sign_up',
142+
type: 'date'
143+
}))
144+
.append($('<label for="user_time_of_birth_1i">Time select</label>'))
145+
.append($('<input />', {
146+
type: 'hidden',
147+
id: 'user_time_of_birth_1i',
148+
name: 'user[time_of_birth(1i)]',
149+
value: 1
150+
}))
151+
.append($('<input />', {
152+
type: 'hidden',
153+
id: 'user_time_of_birth_2i',
154+
name: 'user[time_of_birth(2i)]',
155+
value: 1
156+
}))
157+
.append($('<input />', {
158+
type: 'hidden',
159+
id: 'user_time_of_birth_3i',
160+
name: 'user[time_of_birth(3i)]',
161+
value: 1
162+
}))
163+
.append($('<select>', {
164+
id: 'user_time_of_birth_4i',
165+
name: 'user[time_of_birth(4i)]',
166+
})
167+
.append($('<option value=""></option>'))
168+
.append($('<option value="00">00</option>'))
169+
.append($('<option value="01">01</option>'))
170+
)
171+
.append(':')
172+
.append($('<select>', {
173+
id: 'user_time_of_birth_5i',
174+
name: 'user[time_of_birth(5i)]',
175+
})
176+
.append($('<option value=""></option>'))
177+
.append($('<option value="00">00</option>'))
178+
.append($('<option value="59">59</option>'))
179+
)
180+
.append($('<label for="user_date_of_birth_1i">Date select</label>'))
181+
.append($('<select>', {
182+
id: 'user_date_of_birth_1i',
183+
name: 'user[time_of_birth(1i)]',
184+
})
185+
.append($('<option value=""></option>'))
186+
.append($('<option value="2015">2015</option>'))
187+
.append($('<option value="2016">2016</option>'))
188+
)
189+
.append($('<select>', {
190+
id: 'user_date_of_birth_2i',
191+
name: 'user[time_of_birth(2i)]',
192+
})
193+
.append($('<option value=""></option>'))
194+
.append($('<option value="1">January</option>'))
195+
.append($('<option value="2">February</option>'))
196+
)
197+
.append($('<select>', {
198+
id: 'user_date_of_birth_3i',
199+
name: 'user[time_of_birth(3i)]',
200+
})
201+
.append($('<option value=""></option>'))
202+
.append($('<option value="1">2</option>'))
203+
.append($('<option value="2">2</option>'))
204+
)
136205
$('form#new_user').validate()
137206
},
138207

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

224+
QUnit.test('Validate when focusouting on date_field', function (assert) {
225+
var form = $('form#new_user')
226+
var input = form.find('input#user_date_of_sign_up')
227+
var label = $('label[for="user_date_of_sign_up"]')
228+
229+
input.trigger('focusout')
230+
assert.ok(input.parent().hasClass('field_with_errors'))
231+
assert.ok(label.parent().hasClass('field_with_errors'))
232+
})
233+
234+
QUnit.test('Validate validations of date_select', function (assert) {
235+
var form = $('form#new_user')
236+
237+
//var label = $('label[for="user_date_of_birth_1i"]')
238+
var input_year = form.find('select#user_date_of_birth_1i')
239+
var input_month = form.find('select#user_date_of_birth_2i')
240+
var input_day = form.find('select#user_date_of_birth_3i')
241+
242+
input_year.trigger('focusout')
243+
assert.ok(input_year.parent().hasClass('field_with_errors'))
244+
245+
input_month.trigger('focusout')
246+
assert.ok(input_month.parent().hasClass('field_with_errors'))
247+
248+
input_day.trigger('focusout')
249+
assert.ok(input_day.parent().hasClass('field_with_errors'))
250+
251+
// showing validation messages doesnt work well with this.
252+
// JS Formbuilder must be customized for these types of fields
253+
// to share error message and hide error only when all 3 selects are valid
254+
255+
})
256+
257+
QUnit.test('Validate validations of time_select', function (assert) {
258+
var form = $('form#new_user')
259+
260+
//var label = $('label[for="user_time_of_birth_4i"]')
261+
var input_hour = form.find('select#user_time_of_birth_4i')
262+
var input_minute = form.find('select#user_time_of_birth_5i')
263+
264+
input_hour.trigger('focusout')
265+
assert.ok(input_hour.parent().hasClass('field_with_errors'))
266+
267+
input_minute.trigger('focusout')
268+
assert.ok(input_minute.parent().hasClass('field_with_errors'))
269+
270+
// showing validation messages doesnt work well with this.
271+
// JS Formbuilder must be customized for these types of fields
272+
// to share error message and hide error only when all 3 selects are valid
273+
})
274+
275+
155276
QUnit.test('Validate when focusouting', function (assert) {
156277
var form = $('form#new_user')
157278
var input = form.find('input#user_name')

vendor/assets/javascripts/rails.validations.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -632,6 +632,8 @@
632632

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

637639
if (nestedMatches) {

0 commit comments

Comments
 (0)