Saturday, April 21, 2012

Javascript : From - To Date Validation

Working with javascript(jQuery) and rails really makes me happy.
This time I wanted to add validation messages for from and to dates for nested attributes.

As per my previous post we have already seen the link_to_remove_association for adding confirmation message. But this time the situation is bit different. I want to add validation messages next to the fields of the nested attributes. So those validations run for each field.

Adding function and comparing 2 dates might not be much difficult but becomes tricky, because I am using simple_form_for which wraps in divs. So need to work around the after build html source for exact tree structure.

Well, the view code was something like below(haml file) and check the valid_from and valid_to date fields on which the javascript function needs to be added. So added a function call in onfocus and passed as a parameter input_from to the simple_form_for input.
          = f.input :name, :label => false, :input_html => {:class => 'name'}
          = f.input :description, :label => false, :input_html => {:class => 'description'}
          = f.input :valid_from, :as => :string, :label => false, :input_html => {:class => 'valid_from', :onfocus => "createDatePickerWithValidation(this, 'from', '#{t :selected_date_prior_to_today}', '#{t :selected_both_dates_prior_to_today}');"}
          = f.input :valid_to, :as => :string, :label => false, :input_html => { :class => 'valid_to', :onfocus => "createDatePickerWithValidation(this, 'to', '#{t :selected_date_prior_to_today}', '#{t :selected_both_dates_prior_to_today}');"}
          = link_to_remove_association "X", f, { :onClick => "confirm_for_remove_record(this, '#{t :confirm_for_remove_record}', 10)" }
        %td{:valign => "top"}
          %span{:style=>"display: none; color: #B94A48"}

In javascript file added below function (I usually create common.js).
/* createDatePickerWithValidation(field, type, field_message, combined_message)
*    Datepicker with warning messages for valid from and through dates 
*    warning_div :   is the div in which the warning message is displayed. 
*                    This needs to be searched dynamically for each record based 
*                    on the position of the clicked field.
*    other_field :   is the field seareched based on the clicked field. 
*                    If the clicked field is valid_from then other_field will be valid_to and vice versa.
*                    This is based on each records fields so that it will not conflict to other records.
*    field_message : is the combination of values of both the fields of each record.
*                    First value will always be the valid_from and other will be valid_to.
function createDatePickerWithValidation(f, typ, message, both_fields_message) {
  $(f).datepicker({ dateFormat: 'yy-mm-dd',
    onSelect: function(date) {
      var todays_date = new Date();
      var input_date = new Date( date );
      var warning_div, other_field, field_message;

        warning_div = $(f).closest("td").next().next().next().children();
        other_field = $(f).closest("td").next().children().children().children();
        field_message = date + " and " + other_field.val()
        warning_div = $(f).closest("td").next().next().children();
        other_field = $(f).closest("td").prev().children().children().children();
        field_message = other_field.val() + " and " + date
      /* Default warning message set */
      var msg = ""
      var other_field_date = new Date( other_field.val() );

      /* If both input dates are prior to today's date */
      if( todays_date > input_date && todays_date > other_field_date ){
        msg = field_message + both_fields_message

      /* If clicked input is prior to todays date but other field is blank or after todays date */
      if( todays_date > input_date && ( todays_date <= other_field_date || other_field.val()=="" ) ){
        msg = date + message

      /* If other field is prior to todays date but clicked input is blank or after todays date */
      if( todays_date > other_field_date && ( todays_date <= input_date || date=="" ) ){
        msg = other_field.val() + message

      /* If message blank then remove the text and hide the div else add text and show div */
and in en.yml
  selected_date_prior_to_today: " date is prior to todays Date"
  selected_both_dates_prior_to_today: " dates are prior to todays Date"


  1. Fine, but these are old way of doing. Things are moved ahead use jQuery validator and start using ujs.

    1. Yes, that's right, but the solutions I add on the blog, I consider should work for all the languages and not only for ruby on rails application. So that with the minimum changes these scripts should work for any web based application.