Meteor-Community-Packages / meteor-autoform-bs-datepicker

Custom "bootstrap-datepicker" input type for AutoForm
MIT License
25 stars 32 forks source link

Validation ignores entered text in favor of autoselected date when forceParse: false #45

Open alexcorre opened 8 years ago

alexcorre commented 8 years ago

The issue

We use a datepicker field with options {forceParse: false, autoclose: true}

An example use:

{{> afQuickField
    name="startDate"
    placeholder="MM/DD/YYYY"
    type="bootstrap-datepicker"
    datePickerOptions=datePickerOptions
}}

According to bootstrap datepicker docs the forceParse option can be used to control the following behavior:

Whether or not to force parsing of the input value when the picker is closed. That is, when an invalid date is left in the input field by the user, the picker will forcibly parse that value, and set the input’s value to the new, valid date, conforming to the given format.

When forceParse is set to false the user typed text remains in the <input type="text"> created by aldeed:autoform-bs-datepicker but when validation runs, the valueOut function ignores text that is in the input and returns only the value that is selected in the datepicker itself, which is confusing to the user when an incorrectly formatted date is entered. This behavior is very clear from the valueOut code here.

Example

An example with forceParse: false and a user attempting to enter a date:

User enters a string into the input that does not match MM/DD/YYYY format. The bootstrap datepicker does not try to parse, and keeps todays date selected by default:

image

When the user blurs the field, as directed by forceParse option, boostrap datepicker does not attempt to parse the user input so it leaves it intact:

image

At this point I would expect validation to fail when I tried to submit this form since the valueOut should be the string I entered, rather than a Date object from the datepicker.

Instead, there are no validation errors and the valueOut is actually todays date, the date that was autoselected inside boostrap datepicker.

image

You can see the values at this breakpoint here:

image

thus valueOut returns the 7/27 Date object rather than attempting to parse the text that the users can see on the form.

Potential Fix

valueOut should always favor the text in the input rather than the selected date, and attempt to parse it using moment and the configured format on the datepicker. In the event of forceParse: false we would see validation errors, and in the case of forceParse: true the value in the text input should always match that which is currently selected in the picker.

In the event that the user enters an incorrect format and forceParse is false they would be aware of their mistake by a validation failure on the form.

Ajaxsoap commented 8 years ago

Hi @alexcorre, I had this similar problem not long time ago, what I did was use the update method here like this:

$( 'input[name=picker2]' ).datepicker( 'update', new Date( value ) );

My use case is that, the value is computed from a change event from another datepicker something like this:

'change input[name=picker1]': function ( event, template ) {
    var target = $( event.target ).val();
    var duration = moment.duration( parseInt( range, 10 ), 'months' );
    // range is coming from a reactive variable from another select input (string)
    var value = moment( new Date( target ) ).add( duration ).format( 'MM-DD-YYYY' );
    template.$( 'input[name=picker2]' ).val( value ); // to display the value on the input
    if ( target ) {
      $( 'input[name=picker2]' ).datepicker( 'update', new Date( value ) );
    }
  }

End result/value for picker2 is picker1 plus n months. The date selected on the datepicker (picker2) is the actual value on the input.

In your case is thru user input, maybe try capturing the input value and pass it on the datepicker using the update method.

I hope this helps.