amsul / pickadate.js

The mobile-friendly, responsive, and lightweight jQuery date & time input picker.
http://amsul.ca/pickadate.js
MIT License
7.7k stars 1.01k forks source link

Picker opening when leaving / coming back to browser window #160

Open happypoulp opened 11 years ago

happypoulp commented 11 years ago

First of all, Pickadate is just awesome (well built, great api, highly extensible, a pleasure to work with).

Thanks for it, I just discoverd it and I feel that it will become my only reference for date/time picker.

I did find a small issue that I think can be easily fixed:

Steps to reproduce:

1) Go on http://amsul.ca/pickadate.js/index.htm 2) Click on the first picker input 3) Click on a date to choose one (picker should close itself) 4) Click out of browser window 5) Click in the browser window (anywhere in the page) 6) BUG: The picker opens without the user clicking on it

Tested on Google Chrome Version 27.0.1453.110

I hope you have enough infos to fix, keep on the great work!

brunogaspar commented 11 years ago

It's a focus/blur thing, i've done this to fix it

onClose: function() {
    $('.datepicker').blur();
}

I've done this for both date and time pickers.. but yeah it's annoying

happypoulp commented 11 years ago

Thanks for the tip, I'll do that for now.

amsul commented 11 years ago

Once again, @brunogaspar, thanks for the quick tip.

The only shortcoming of this solution is that the users lose their tabindex flow – which can be especially annoying if the field falls within a long form.

The only solution off the top of my head is to watch the page visibility api. When the user focuses onto the page and the date input was the last focused element, trigger a picker.close(true) to keep it closed with focus.

brunogaspar commented 11 years ago

I noticed an issue, not sure if it is related to the snippet i posted, but if i press the enter key it opens the date/picker-picker, my workaround was to disable the enter key on forms that has date/time pickers, but i haven't done much testing to see what is the cause.

soaptray commented 11 years ago

@brunogaspar, the solution works for me - thank you.

Winni- commented 10 years ago

Same, annoying thing.

darrenhaken commented 10 years ago

@amsul should we be aiming to add our own event hooks with the page visibility API or is this something that can be added to the API?

amsul commented 10 years ago

@darrenhaken, you’d have to add your own event hooks - there’s nothing within the API that compensates for it just yet..

lijunle commented 10 years ago

@amsul why not include @brunogaspar 's solution to the project's code.

onClose: function() {
    $('.datepicker').blur();
}

I consider this as a bug. :bug:

amsul commented 10 years ago

@lijunle because that’s not really great for accessibility. You lose keyboard focus from the input field.

The right way to do it is by checking the page visibility and closing it with focus if needed.

I’ve marked this for release in v3.6. If someone wants to take a stab at it, please feel free to :)

lijunle commented 10 years ago

Hi, @amsul . Thanks for your reply,

I do not get your meaning of

The right way to do it is by checking the page visibility and closing it with focus if needed.

Could you please explain more?

amsul commented 10 years ago

@lijunle yeah, in a comment above I wrote:

The only solution off the top of my head is to watch the page visibility api. When the user focuses onto the page and the date input was the last focused element, trigger a picker.close(true) to keep it closed with focus.

Here’s the page visibility API: https://developer.mozilla.org/en-US/docs/Web/Guide/User_experience/Using_the_Page_Visibility_API

lijunle commented 10 years ago

@amsul

I don't think the datepicker should pop up once the input box is focus. Split the focus and date picker pop up to two stages is better:

  1. Use TAB to loop over the input boxes.
  2. When datepicker input box is focused, input box show "press space or enter to show date picker".
  3. Then press space or enter, datepicker pops up.
  4. Press esc to close the pop up dialog, the return to point 2.

With this approach, there is no need to use visibility API. How do you think about this?

amsul commented 10 years ago

@lijunle that’s an interesting approach.

Although, I feel that it should only be split into two steps if there’s a way to enter data without the picker being opened.

That’s why the native date input on desktop splits it into a separate "dropdown" button, whereas on mobile it's a one tap action because it’s the only way to enter a value.

But regardless, using the current API, you can already achieve the mechanics you’re proposing by initializing like this:

$('#input').pickadate({
    editable: true
})

..and then binding a focus event that does something like this:

$('#input').on('focus', function() {
    // open the picker when enter/space is pressed
})
thanpolas commented 9 years ago

So any progress on this? It's been nearly 2 years for such an apparent bug

RobertLowe commented 9 years ago

I just did:

$picker.on 'close', ()->
  $(document.activeElement).blur()

To prevent the re-opening after switching tabs

rroblik commented 9 years ago

@RobertLowe working nice : )

Thanks

jpfortier commented 9 years ago

I added a check onOpen to see if the target class is already present. Does the job well enough for my situation:

$input.pickadate({
    onOpen: function () {
        if ($input.hasClass('picker__input--target')) {
            $input
                .pickadate()
                .pickadate('picker')
                .close(true);
        }
    }
});
totaskin commented 9 years ago

@RobertLowe thanks, got this working with:

onClose: function(){
        $(document.activeElement).blur()
    }
jambox commented 9 years ago

Yea thanks @RobertLowe. Your solution worked better than trying to target the right element via a class selector.

aravindsanker commented 9 years ago

@lijunle Where do i add the code you have suggested ? Thanks.

lijunle commented 9 years ago

@aravindsanker which suggestion do you refer to? The onClose one, or this post? For the first one, add it to pickadate initialization option object. For the second one, I have not try to implement it.

davidchoo12 commented 8 years ago

I found out I have to blur the .picker div as well after I blurred the .datepicker div So my code is:

onClose: function(){
        $('.datepicker').blur();
        $('.picker').blur();
}
ShaheensWeb commented 8 years ago

@RobertLowe Thank you so much, best solution in the thread.

benpolinsky commented 8 years ago

Why isn't this documented?

sinneren commented 8 years ago

@jpfortier it's working, and only it, but only with first input. With second already not

waheed1987 commented 8 years ago

I have chosen this approach, maybe it helps

jQuery(window).blur(function() {
    var $focused = jQuery(document.activeElement);
    if ($focused.hasClass('picker__holder')) {
        jQuery(document.activeElement).blur();
    }
});
jtouzy commented 8 years ago
onClose: function(){
  $(document.activeElement).blur();
}

Works for me too. It appears to be a bug : should release the focus when the dialog is closing.

adrianmihalko commented 7 years ago

Guys, I want to go to next field if I press TAB, but Datepicker is opening. I am already tried the blur method, but it's not working. Maybe because I am using date and time picker together?

$(document).ready(function()          
    {

      var datepicker = $('#date').pickadate({
        formatSubmit : 'yyyy-mm-dd',
        hiddenSuffix: 'date_submit',
        firstDay: 1,
        container: '#outlet',
        onSet: function(item) {
            if ( 'select' in item ) setTimeout( timepicker.open, 0 )
        }
    }).pickadate('picker')

var timepicker = $('#time').pickatime({
        min: [09,00],
        max: [17,00],
        format: 'HH:i',
        formatSubmit: 'HH:i'+':00',
        hiddenSuffix: 'time_submit',
        container: '#outlet',
        onRender: function() {
            $('<button class="picker__button--clear">Vissza</button>').
                on('click', function() {
                    timepicker.close()
                    datepicker.open()
                }).prependTo( this.$root.find('.picker__box') )
        },
        onSet: function(item) {
            if ( 'select' in item ) setTimeout( function() {
                $datetime.
                    off('focus').
                    val( datepicker.get() + ' @ ' + timepicker.get() ).
                    focus().
                    on('focus', datepicker.open)
            }, 0 )
        }
    }).pickatime('picker')

var $datetime = $('#tm').
    on('focus', datepicker.open).
    on('click', function(event) { event.stopPropagation(); datepicker.open() })

      $('#form').on('keyup keypress', function(e) {
        var code = e.keyCode || e.which;
        if (code == 13) { 
          e.preventDefault();
          return false;
        }
      });
        // enter keyd
        $("body").keypress(function(e) {
            if(e.keyCode==13 && e.ctrlKey) {
              $('#form').submit();  
              }     
        });
    });    
dellert commented 7 years ago

@adrianmihalko I have same problem

sn3ka commented 7 years ago

Hi, actually in my case

onClose: function(){$('.picker').blur();}

was not working. I had to blur the holder of the picker box with:

onClose: function() {$(".picker__holder").blur();}

ecumike commented 7 years ago

This is how you fix it properly... add this to your pickadate config when you set it and it will blur the particular instance that was closed, and not ALL instances (as the above code does):

onClose: function () {
    this.$holder.blur();
}
leonardovillela commented 7 years ago

@adrianmihalko Did you solve your problem? In my case even with the input disabled the tab opens the picker

K1911 commented 7 years ago

The "reopening calendar" has bugged me too but the solution I found today was very easy:

// input_pickadate is the html input text: if the user click it we authorize picker to open
var input_pickadate = $('input[name="date"]').pickadate();

// the picker
var picker = $(input_pickadate).pickadate('picker');

input_pickadate.on( 'click', function(e){
        e.stopImmediatePropagation(); // does not seem to work
        $(picker).data( 'stay_open', true );
        picker.open();
});

picker.on( 'open', function(){
       if( !$(picker).data('stay_open') ){
            picker.close();
       }
});

// auto reopen is disallowed
picker.on( 'close', function(){
       $(picker).data( 'stay_open', false );
});

The only glitch is that the event 'open' is fired three times. I dont know why but there are not visual artifacts.

CB-Sean commented 7 years ago

@hidingmode After trying every solution in this thread, this is the combination that worked for me. I have to close both the .datepicker and the .picker elements.

poziman commented 7 years ago

@RobertLowe thanks a lot!

samber commented 6 years ago

This worked for me:

onClose: () => {
  $(":focus").blur();
},
shockalotti commented 6 years ago

I tried them all.

None worked.

But putting this before the config options worked:

$(function () { $('.datepicker').blur(); });

shockalotti commented 6 years ago

This is so hacky... but I found. putting a hidden "dummy" input before the pickadate one stopped the unwanted behaviour.

RBakerBluestone commented 6 years ago

I've tried every solution on this page. Nothing works.

This always seems to happen when using external libraries. You save time by implementing an external library, then you find some bug. You search and find posts offering a million solutions that do not work going back years (five in this instance).

It's probably best to build something like this from scratch that works exactly as you imagine. Honestly, how difficult can it be?

RobertLowe commented 6 years ago

Says the guy who joined github 15 minutes ago...

You should adjust your attitude here's why:

  1. This is free, you didn't pay anything for it, read the MIT License, nobody owes you anything.
  2. Not all applications behave the same, not all devices behave the same, thusly increasing complexity, for someone whom is paid nothing, they cannot promises assurances
  3. Instead of non-constructive feedback/complaining, take up arms and offer a solution

How difficult can it be. Very, that's why software professionals have a job, nothing is perfect.

On a side note, yes, you'll need to go through many resources to find a solution for a specific problem, and over time, you gain something called experience which helps you adapt and manage problems with greater ease.

RBakerBluestone commented 6 years ago

Sorry, I didn't mean any offense. I did just create a github account so I could leave a comment. I'll concede that my commentary was unwarranted, and that of course nothing is owed to me.

This is the solution I found that worked for me:

var calendar_closed=false;  // global variable to track if the calendar was closed.

// inside pickadate declaration...
onOpen: function() { 
      if (calendar_closed) { calendar.close(); }  // calendar is a reference to the pickadate object
      calendar_closed=false;
},
onClose: function(e) { calendar_closed=true; }

Perhaps others can rewrite this without the use of a global variable. Right now, this is good enough for me.

Hope this helps.

Edit: updated code to work for a more generic situation.

@RobertLowe - PS, you were pretty great in The Outsiders. Cheers!

DanielRuf commented 6 years ago

Hi, thanks for the update.

Is there something that we can do / fix in pickadate to prevent this?

RBakerBluestone commented 6 years ago

It would be nice if the datepicker did not automatically reopen when a user returns to the browser tab.

For example:

  1. Navigate to http://amsul.ca/pickadate.js/
  2. Click on the first 'Try Me' to have the date picker open
  3. Select a date from the date picker. The date picker should now hide.
  4. Open and navigate to a new browser tab.
  5. Return to the http://amsul.ca/pickadate.js/ tab. The date picker opens again.

I was able to make a simple solve by creating a global variable that tracked whether the date picker had been closed and use it in the onOpen & onClose events. My fix is a kludge, but perhaps a similar but more elegant solution can be incorporated into pickadate.

DanielRuf commented 6 years ago

I think it is related to some focus.

neurot1k commented 5 years ago

Adding document.activeElement.blur(); to onClose solved this issue for me in v3.6.0

castrocristiano commented 5 years ago

Adding document.activeElement.blur(); to onClose solved this issue for me in v3.6.0

It works for me:

image

Thank's.

DanielRuf commented 5 years ago

https://github.com/amsul/pickadate.js/issues/160#issuecomment-74816391

So this is not new ;-)

Would like someone to create a PR for this?