Usar un datepicker con Rails, JQuery, Twitter Bootstrap y SimpleForm
Todos sabemos que la manera más rápida de introducir una fecha es usar el teclado y un simple campo de texto; sin embargo nuestros usuarios no usan el ordenador tantas horas al día ni llevan tantos años haciéndolo como nosotros, por lo que no les importa destrozarse un poco más la muñeca usando el ratón y pinchando en un bonito calendario.
A la hora de intentar usar algún tipo de calendario para introducir las fechas nos encontramos con dos problemas:
- El bootstrap no incluye ninguno de serie.
- Los estilos de la librería JQuery UI no son compatibles con él, por lo que si intentamos usar el datepicker de éste, se va a ver fatal.
Mi objetivo es poder usar un datepicker en el que pueda especificar la fecha que se muestra inicialmente en el calendario mostrado, o si no indico nada, que coja la actual. La versión de Rails utilizada en este ejemplo es la 3.2.3, y las gemas son: bootstrap-sass 2.0.2 y simple_form 2.0.2
Tras googlear un poco encontré la página de Stefan Petre, autor de un Colorpicker y un Datepicker bastante resultones.
Insertar el código del datepicker
Tras descargarlo, lo único que hay que hacer es copiar el css y js que lo forman en nuestra carpeta de assets (obviamente en stylesheets y javascripts, respectivamente), y tal como indica la documentación, utilizarlo es tan sencillo como lo siguiente(los inputs de fechas en mi app llevan la clase date_picker):
$(document).ready(function() {
$("input.date_picker").datepicker({format: 'yyyy-mm-dd', weekStart: 1});
})
Por defecto, cuando pulsamos en el input, aparece el calendario mostrando la fecha que aparezca en su value; si éste es nulo, aparecerá el 1 de enero de 1900, que raramente será lo que queremos. Por otro lado este plugin contempla el caso de no usar un input, y entonces coge por defecto la fecha que indiquemos en el atributo data-date de la etiqueta en cuestión.
En mi caso me interesa usar inputs, y no quiero asignar un value inicial, por lo que para usar un atributo data-date en los input podemos modificar el fichero bootstrap-datepicker.js, y la línea 115 (método update) la modificamos para tener esto:
this.date = DPGlobal.parseDate( (this.isInput && (this.element.prop('value') != "")) ? this.element.prop('value') : this.element.data('date'), this.format );
Una vez hecho esto, añadiendo data-date="2012-10-12" conseguiríamos un input vacío pero con el calendario inicializado en esa fecha.
Crear un tipo específico de input para el SimpleForm
A la hora de usarlo con el SimpleForm, para evitar tener que escribir continuamente líneas como:
<%= f.input :begin_date, :as => :string, :input_html => {:class => 'span2 date_picker', "data-date" => "2012-10-12" } %>
se puede crear una clase que defina un nuevo tipo de input. Para ello creamos un fichero en app/inputs/ denominado date_picker_input.rb, y creamos nuestra clase:
class DatePickerInput < SimpleForm::Inputs::StringInput
def input
input_html_classes.push 'span2'
super
end
def input_html_options
options[:date] ||= Date.today
super.merge('data-date' => options[:date])
end
end
Ahora podemos usar nuestro propio input en los formularios así:
<%= f.input :begin_date, :as => :date_picker %>
<%= f.input :birthdate, :as => :date_picker, :date => Date.new(1940, 1, 1) %>
Solución de problemas
Aunque (en teoría) por defecto el SimpleForm lee los inputs propios que hayamos definido en la carpeta app/inputs, es posible que no lo haga (fué mi caso); si nos pasa esto basta editar config/initializers/simple_form.rb y descomentar la línea:
config.inputs_discovery = true
Por otro lado, el plugin incluye los meses y días en inglés, por lo que tendremos que localizar los arrays oportunos en el fichero bootstrap-datepicker.js y cambiarlos al español si es lo que necesitamos. Lo ideal sería prepararlo para usar i18n.
Generalización
Si todos nuestros inputs de fecha van a llevar el datepicker, y además todos incluyen la palabra date en su nombre, podemos hacer que automáticamente sean de tipo date_picker sin tener que especificarlo, incluyendo en el config/initializers/simple_form.rb lo siguiente:
config.input_mappings = { /date/ => :date_picker }
Y con esto nuestros formularios vuelven a ser concisos:
<%= f.input :begin_date %>
<%= f.input :birthdate, :date => Date.new(1940, 1, 1) %>
Es posible que haya algun otro plugin mejor por áhí. ¿Has probado algún otro que se pueda usar con comodidad? Cualquier sugerencia será bienvenida.