I am trying to put together a working solution for using the date_field HTML5 date controls when the browser supports it and fall back to use the Bootstrap Datepicker if not. It seems like this is a common scenario to tackle but I haven't been able to find a solution that works for me (namely, one that doesn't involve manually adding a hidden field for every date field since I already have a bunch across a number of pages).
Using this writeup as a guide I have a partially working solution (using FireFox 49.0.2 to test):
dates.js.coffee:
datepicker = $.fn.datepicker.noConflict() # return $.fn.datepicker to previously assigned value
$.fn.bootstrapDP = datepicker # give $().bootstrapDP the bootstrap-datepicker functionality
formatDateToPicker = (dateStr) ->
# dateStr is what Rails emits "yyyy-mm-dd"
parts = dateStr.split('-')
if dateStr == ''
return 'NoDateProvided'
else if parts.length == 3
return "#{parts[1]}/#{parts[2]}/#{parts[0]}"
else
return 'InvalidISODate'
formatDateFromPicker = (dateStr) ->
# dateStr is what the datepicker emits "mm/dd/yyyy"
parts = dateStr.split('/')
if dateStr == ''
return ''
else if parts.length == 3
return "#{parts[2]}-#{parts[0]}-#{parts[1]}"
else
return 'Invalid picker date'
set_datepicker_dates = () ->
$("input[type='date']").each (i,e)=>
$e = $(e)
# create a hidden field with the name and id of the input[type=date]
$hidden = $('<input type="hidden">')
.attr('name', $e.attr('name'))
.attr('id', $e.attr('id'))
.val($e.val())
# modify the input[type=date] field with different attributes
$e.attr('hidden-id', $e.attr('id')) # stash the id of the hidden field
.attr('name', "")
.attr('id', "")
.val(formatDateToPicker($e.val())) # transform the date
.after($hidden) # insert the hidden field
# attach the picker
$e.bootstrapDP({
#format: 'mm/dd/yyyy',
autoclose: true,
todayBtn: "linked",
todayHighlight: true,
clearBtn: true
})
# update the hidden field when there is an edit
$e.on 'change', (e)=>
$e = $(e.target)
$v = $('#' + $e.attr('hidden-id'))
$v.val(formatDateFromPicker($e.val()))
$(document).on 'turbolinks:load', ->
if ($("input[type='date']").length > 0)
unless Modernizr.inputtypes.date
set_datepicker_dates()
show.html.erb:
<%= f.date_field :dateofbirth, placeholder: 'mm/dd/yyyy', class: 'form-control' %>
This works for normal turbolinks-based browsing/rendering, HOWEVER when I do a full browser refresh it sets the dates to "InvalidISODate". I've tried calling set_datepicker_dates()
on document ready and window onload as well but neither works. Many thanks in advance for any guidance.
Update
I am now trying to get just the Bootstrap datepicker working across the board (i.e. instead of a combination of one of those and the browser's native HTML5 datepicker if available), but to no avail. My database is PostgreSQL and my date fields in the db are of type 'date', thus the default datestyle of 'ISO, MDY' is being used. I have the following code currently set up:
gemfile:
gem 'bootstrap-datepicker-rails'
application.js:
//= require bootstrap-datepicker
application.scss:
@import "bootstrap-datepicker3";
date_format.rb:
Date::DATE_FORMATS[:default] = "%m/%d/%Y"
dates.js.coffee:
$(document).on 'turbolinks:load', ->
$('.datepicker').datepicker()
edit.html.erb:
<%= f.text_field :dateofbirth, placeholder: 'mm/dd/yyyy', class: 'form-control datepicker', autocomplete: 'off' %>
What is happening now is that I will select 02/01/2017 from the picker, it gets submitted as '2017-01-02' and thus saved to the database as Jan 1st 2017 so that when I do <%= object.dateofbirth %>
in a view it is displayed as '01/02/2017'. Am I crazy? I feel crazy. Should I post a new question with my latest attempt/issue?