smalot / bootstrap-datetimepicker

Both Date and Time picker widget based on twitter bootstrap (supports Bootstrap v2 and v3)
http://www.malot.fr/bootstrap-datetimepicker/
Apache License 2.0
3.5k stars 1.65k forks source link

Allow manual edit of date #513

Open chmielot opened 8 years ago

chmielot commented 8 years ago

Hi,

thanks for the great work. I'm using datetimepicker in combination with MopaBootstrapBundle in a Symfony2 project. I followed these instructions here to integrate it: https://github.com/phiamo/MopaBootstrapBundle/blob/master/Resources/doc/form/4-form-components.md

I also read the documentation of datetimepicker back and forth but I can't find a way to allow the user to edit the date manually. Some users want to edit date or time manually because they are faster with it. Everytime I change the input value it's set back to the last value after datetimepicker is closed. If I first close the picker and then edit the value nothing happens on blur and the old value is submitted in the form. The datetimepicker demo shows readonly fields.

Is there a way to allow the user to override the value manually without using the datetimepicker?

benjaminsp commented 8 years ago

same problem

AuspeXeu commented 8 years ago

How did you download this library?

jkarr commented 7 years ago

I'm having the same problem. Have you found a resolution yet?

chmielot commented 7 years ago

@AuspeXeu Sorry it took me so long to answer, I'm now back into that topic. As said in my initial description I'm using the library via the integration of MopaBootstrapBundle. Even after updating to the most recent version of this libarary I have the same behaviour. On the demo site unfortunately all input controls are read-only, so you're not able to test this use case. I prepared a jsfiddle for you:

https://jsfiddle.net/chmielot/umca5svy/2/

Steps to reproduce:

  1. Click into the right side of the input field, so that the cursor stops behind the year 1980
  2. Press backspace once, enter 8. Now you read 1988 as the year
  3. Let the field lose focus by clicking somewhere else
  4. The year changes back to 1980

Expected behaviour: Year stays as 1988 and is submitted like that with the form.

Can you please assist?

chmielot commented 7 years ago

@AuspeXeu Can you at least tell me, if the library is even supposed to allow manual edit of dates and times? As said, the demo page doesn't even have one example that is not read-only.

AuspeXeu commented 7 years ago

@chmielot I am sorry, but I don't maintain the demo page. It was created by the initiator of this project. However, I am using the library for my own projects and the behaviour is fine there. I am not sure what the difference is here.

chmielot commented 7 years ago

@AuspeXeu To be environment agnostic I prepared the jsfiddle. Can you either share the piece of code of your project so I can compare or could you have a quick look yourself? It seems to me, that I'm not doing anything special in the fiddle, everything is plain standard, nothing fancy... And you say that you can't reproduce the behaviour described for the fiddle in your own projects?

AuspeXeu commented 7 years ago

@chmielot that is exactly what I say, yes. I amusing the following links to include the library.

https://cdnjs.cloudflare.com/ajax/libs/smalot-bootstrap-datetimepicker/2.3.8/css/bootstrap-datetimepicker.min.css https://cdnjs.cloudflare.com/ajax/libs/smalot-bootstrap-datetimepicker/2.3.8/js/bootstrap-datetimepicker.min.js

I know this is an older version than yours but when I put this version in you jsfiddle I have the same issues you describe. So I would assume it has to do something with the way you create/configure the datetimepicker. The code in my project looks like this:

HTML code

<input type="text" class="dtp" data-date-format="hh:ii dd.mm.yyyy">

and the relevant in initialisation JS code

$('.dtp').datetimepicker({
  autoclose: true,
  todayBtn: true,
  todayHighlight: true
})
$('.dtp').datetimepicker('setDate', new Date())
chmielot commented 7 years ago

@AuspeXeu Sorry for the long delay, I investigated even more. The main difference between your simple example and mine is that MopaBootstrapBundle uses a linked (mirror) field by default, to always submit a date in Y-m-d H:i:s format.

Unfortunately the datepicker component relies on the fact that the editable field always comes first in DOM tree, followed by the hidden (linked) field. This is due to a lot of locations doing: element = this.element.find('input'); to find the editable field.

The fix for this is simple, I just changed the order of the fields:

<div  data-provider="datepicker" class="input-group date" data-date="1980-01-13" data-link-field="pdb_promoterbundle_promotertype_birthday" data-link-format="yyyy-mm-dd">
    <input type="hidden" value="1980-01-13" id="pdb_promoterbundle_promotertype_birthday" name="pdb_promoterbundle_promotertype[birthday]" required="required">
    <input type="text" id="pdb_promoterbundle_promotertype_birthday_mopa_picker_display" name="" required="required" class="form-control" value="1980-01-13" />
    <span class="input-group-addon"><span class="glyphicon glyphicon-calendar"></span></span>
</div>

to

<div  data-provider="datepicker" class="input-group date" data-date="1980-01-13" data-link-field="pdb_promoterbundle_promotertype_birthday" data-link-format="yyyy-mm-dd">
    <input type="text" id="pdb_promoterbundle_promotertype_birthday_mopa_picker_display" name="" required="required" class="form-control" value="1980-01-13" />
    <span class="input-group-addon"><span class="glyphicon glyphicon-calendar"></span></span>
    <input type="hidden" value="1980-01-13" id="pdb_promoterbundle_promotertype_birthday" name="pdb_promoterbundle_promotertype[birthday]" required="required">
</div>

This brought me closer to a solution but unfortunately there is one issue left. I prepared a jsfiddle again with the newest library included: https://jsfiddle.net/chmielot/akapLr0p/

Working scenario (A):

  1. Click between 8 and 0 of the year 1980 in the editable datetimepicker text input (note that the calendar opens, leave it open, just follow the steps)
  2. Press backspace and change 8 to 9, the value becomes 1990.
  3. Click on "Show values", you receive the expected result.

Non-working scenario (B):

  1. Click between 8 and 0 of the year 1980 in the editable datetimepicker text input. The calendar pops up. Click in the exact same location again which makes the calendar disappear. Alternatively you can close the calendar popup by pressing escape.
  2. Press backspace and change 8 to 9, the value becomes 1990.
  3. Click on "Show values", you can see that the mirror field was not updated.

Scenario A works, because clicking outside of the calendar (by clicking on "Show values") calls clickedOutside which calls that.hide() which eventually calls setValue in line 433. When the calendar is not visible anymore like in Scenario B, the values are not updated because hide exits early.

I thought about hooking into the calendar hide method, as everything works fine while the calendar is open. Please review my pull request and tell me if you need adjustments or if this is not the correct location for a fix. It shouldn't break anything else and seemed to be the most straightforward change.

Please find a working jsfiddle with the code changes applied here: https://jsfiddle.net/chmielot/vhf09gzm/

Feedback or merge is highly appreciated.

chmielot commented 7 years ago

@AuspeXeu Kindly asking for feedback

chmielot commented 7 years ago

@AuspeXeu Is the proposed solution valid or do you want me to change something?