Tempus-dominus: widgetParent positions the picker incorrectly

Created on 28 Jan 2015  路  62Comments  路  Source: Eonasdan/tempus-dominus

See http://jsfiddle.net/cmpgtuwy/5/

Attaching the picker to a relatively positioned element positions the element incorrectly.

I came across this because I wanted the same behaviour that existed in v3 - the picker is attached to the body element, but positioned under the input element (very useful for dialogs, as it allows the picker to overflow the body of the dialog).

Could we please have some way to get this behaviour back?

v4

Most helpful comment

For those of you pining for the old days of being attached to body!
I hate it but it works....

.on('dp.show', function (e) {
    var datepicker = $('body').find('.bootstrap-datetimepicker-widget:last'),
        position = datepicker.offset(),
        parent = datepicker.parent(),
        parentPos = parent.offset(),
        width = datepicker.width(),
        parentWid = parent.width();

    // move datepicker to the exact same place it was but attached to body
    datepicker.appendTo('body');
    datepicker.css({
        position: 'absolute',
        top: position.top,
        bottom: 'auto',
        left: position.left,
        right: 'auto'
    });

    // if datepicker is wider than the thing it is attached to then move it so the centers line up
    if (parentPos.left + parentWid < position.left + width) {
        var newLeft = parentPos.left;
        newLeft += parentWid / 2;
        newLeft -= width / 2;
        datepicker.css({left: newLeft});
    }
})

I also had to add code to force the immediate parent to have position: relative. In my case this works across the board. But keep in mind that in your case, datepicker.parent() isn't necessarily the correct element to use as parent. Use at your own risk. Modify at your own will :-)

All 62 comments

The whole point of the new positioning algorithm in version 4 is to adapt automatically to the most appropriate relative component, hence not having to deal with positioning on the body element which makes the algorithm much more complicated and fragile (as in version 3, requiring to specify z-index and various other tricks).

Which it does, if you omit the widgetParent option and tweak the widgetPositioning object. Have a look here jsfiddle. I seem to miss your point maybe you could provide a jsfiddle with an actual dialog to demonstrate the problem.

Okay, I've found out how to replicate the issue that I see on my system:

http://jsfiddle.net/cmpgtuwy/7/

It seems that this is caused by setting an overflow property on the modal-body, which prevents the picker widget from overflowing the modal body.

I have the same problem without the modal
First if I don't add the div with class row and the div with class col-xs-12 the calendar don't even show up (would be nice if there were no need of 2 extra divs)

Then I have the same problem @am0d but without the modal
Here's the jsfiddle:
http://jsfiddle.net/9mx6ajaa/

Putting an input inside a table, makes the position of the widget completely wrong.

http://jsfiddle.net/wyrzqq5x/1/
(ps: must be http for bootstrap to work)

I have the same issue where if a certain level container has an overflow:hidden, my picker will not be displayed properly.

I am also facing this issue. Please look at the followimg fiddle,

http://jsfiddle.net/rtzxsa3e/7/

You should follow bootstrap guidelines on properly nesting elements using bootstrap grid system. Otherwise the behavior of positioning the popup will not be the correct one

Same problem here, someone found a workaround or solution?

Thanks

I am having the same problem as well.

Had the same problem with widgetParent and positioning, solved with this commit https://github.com/sibsfinx/bootstrap-datetimepicker/commit/3412d1e910d32bd1c5062926727c2a2ef73a8ce1
Please, test and review it.

I've also added place function to call it when you need to change widget position (for example, on scroll), see this branch https://github.com/sibsfinx/bootstrap-datetimepicker/tree/v4.7.x

@sibsfinx please resubmit your PR to the dev branch

I think we should take into account the margins for vertical positioning 'top' to prevent the picker is too near the input field when the picker appears above.

Here's what I propose:

widget.css({
top: vertical === 'top' ? position.top - widget.outerHeight(true) : position.top + (component || element).outerHeight(true),
left: horizontal === 'left' ? position.left + (component || element).outerWidth() - widget.outerWidth() : position.left
});

We should replace widget.outerHeight() by widget.outerHeight(true)

This is affecting cachethq/cachet too...

The whole point of the new positioning algorithm in version 4 is to adapt automatically to the most appropriate relative component

But now it doesn't work properly....

Yeah, it definitely isn't working as planned...

+1

Save issue as for @jbrooksuk

yeah, jquery dialog, major headache.

How can i append the widget to the body to solve the issue of opening the DTP in a Bootstrap modal?

Any news on this? I'm seeing the widget on top of the page.
The input field is inside a handlebar template

+1, seeing the same behaviour as @jbrooksuk

Same problem here - "overflow: hidden" cuts the picker. Definitely has to be attached to the body. Major show-stopper.

I agree with @lllopo. This is major show-stopper as we definitely need to use this control in scenarios like table and modal dialog.

Had same problem,..

Again not with Dialogs, but a table inside collapsible containers.

Setting WidgetParent to 'body' and applying @sibsfinx fix worked for me.

+1

When we have the datepicker widget within a scroll container overflow-y: scroll; the widget isn't shown completely, it is getting cut-off. I expect it to show outside the parent scroll container when it cannot be shown within the parent scroll container. https://jsfiddle.net/sripad6e/0Ltv25o8/1680/

https://jsfiddle.net/sripad6e/0Ltv25o8/1679/

Setting WidgetParent to 'body' and applying @sibsfinx fix did not worked for me.

I had to move to another library which is based on this library but has no such issues with overflow-y. Check this out -
https://github.com/smalot/bootstrap-datetimepicker#~2.3.4

You will have to add support for moment on your own though if you want to handle time as a moment object.

Any news?

+1 for a solution to the problem of datepicker within scroll container

My current solution... Not perfect, but for now this works ok for my purposes. (Not cross browser tested)

$('.datetimepicker').datetimepicker({widgetParent:'body'})
.on('dp.show', function(){
var top = ($(this).offset().top-300);
var left = $(this).offset().left;
if($(this).offset().top - 400 <= 0) { //display below if not enough room above
top = $(this).offset().top+$(this).height()+10;
}
$('.bootstrap-datetimepicker-widget').css(
{
'top':top+'px',
'left':left+'px',
'bottom':'auto',
'right':'auto'
});
});

My hack is pretty similar:

$('.datetimepicker').on('dp.show', function () { // Hack datepicker position
    var datepicker = $(this).siblings('.bootstrap-datetimepicker-widget');
    if (datepicker.hasClass('top')) {
        var top = $(this).offset().top - datepicker.height() - 180;
        datepicker.css({'top': top + 'px', 'bottom': 'auto'});
    }
});

Quick and dirty fix that worked for me :

        target.parent().css('position', 'relative');
        target.datetimepicker();

Hi all,
thanks for the info so far - I was trying to implement robregonm's hack in a bootstrap modal with multiple datepickers in it but
var datepicker = $(this).siblings('.bootstrap-datetimepicker-widget');
did not return the datepicker - the context is correct but it seems that by the time this is called the datepicker is no longer a sibling of the input element.

I moved to this which seems to work well for me using bottom alignment - hope it helps someone else ;)-:

$('.datetimepicker')
.on('dp.show', function(){
                var datepicker = $("body").find('.bootstrap-datetimepicker-widget:last');
                if (datepicker.hasClass('bottom')) {
                    var top = $this.offset().top + $this.outerHeight();
                    var left = $this.offset().left;
                    datepicker.css({
                                    'top': top + 'px', 
                                    'bottom': 'auto',
                                    'left': left+'px'
                                });
                }
            });

I'm having the same issue of wrong positioning when the input is placed inside a table cell. The datepicker shows at the very bottom left of the page.

I tried @simondubois's suggestion and it worked:

var dateInput = $("#datetimepicker");
// Parent here will be the <td>
dateInput.parent().css("position", "relative");
dateInput.datetimepicker();

Combining the absolute position fixes here:

    target.on('dp.show', function() {
      var datepicker = $('body').find('.bootstrap-datetimepicker-widget:last');
      if (datepicker.hasClass('bottom')) {
        var top = $(this).offset().top + $(this).outerHeight();
        var left = $(this).offset().left;
        datepicker.css({
          'top': top + 'px',
          'bottom': 'auto',
          'left': left + 'px'
        });
      } else if (datepicker.hasClass('top')) {
        var top = $(this).offset().top - datepicker.outerHeight();
        var left = $(this).offset().left;
        datepicker.css({
          'top': top + 'px',
          'bottom': 'auto',
          'left': left + 'px'
        });
      }
    });

works for bottom and top scenarios, widgetParent: 'body' and position:relative on <body>.
I really wished this worked out of the box.

Is there any way to easily override the place function?

@githubjeka You had success using that fix with widgetParent: 'body', while inside an overflow: hidden div?

No

@roooodcastro That is a nice fix, it fixes the issue I had with the picker in a modal being out of place.

Hello,

The solution for me was the following:
http://jsfiddle.net/cmpgtuwy/151/

In the class that has the "overflow: hidden", I put the following code:

.modal-body {
聽聽聽聽 overflow-x: visible! important;
}

.modal-body: after {
聽聽聽聽聽聽聽聽 content: "";
聽聽聽聽聽聽聽聽 clear: both;
聽聽聽聽聽聽聽聽 display: table;
聽}

In the case of the was @am0d .modal-body class, but can be used in another that involving the datepicker.

@roooodcastro solution works for me too

Had the same issue, @roooodcastro (@simondubois) suggestion worked for me

@miguelcobain 's solution worked for situations where the datepicker is inside a scrollable element (or overflow hidden) : http://jsfiddle.net/cmpgtuwy/171/

@Paulmicha solution worked for me! Thanks

@Paulmicha Solution worked for me. Thanks!!
Used datetimepicker in panel-group accordion component.

For me worked put {position:relative;} on the parent container of the input.

For those of you pining for the old days of being attached to body!
I hate it but it works....

.on('dp.show', function (e) {
    var datepicker = $('body').find('.bootstrap-datetimepicker-widget:last'),
        position = datepicker.offset(),
        parent = datepicker.parent(),
        parentPos = parent.offset(),
        width = datepicker.width(),
        parentWid = parent.width();

    // move datepicker to the exact same place it was but attached to body
    datepicker.appendTo('body');
    datepicker.css({
        position: 'absolute',
        top: position.top,
        bottom: 'auto',
        left: position.left,
        right: 'auto'
    });

    // if datepicker is wider than the thing it is attached to then move it so the centers line up
    if (parentPos.left + parentWid < position.left + width) {
        var newLeft = parentPos.left;
        newLeft += parentWid / 2;
        newLeft -= width / 2;
        datepicker.css({left: newLeft});
    }
})

I also had to add code to force the immediate parent to have position: relative. In my case this works across the board. But keep in mind that in your case, datepicker.parent() isn't necessarily the correct element to use as parent. Use at your own risk. Modify at your own will :-)

Hello,

I am having the same issue, any fix for this as of yet?

@palmtown

target.parent().css('position', 'relative');
target.datetimepicker();

@afanasy

Thanks for the prompt response, that worked like a charm! :)

I neglected to zIndex: 9999 //or some other large number as needed in my solution above

I soved doing:
<div style="position:relative"><input type='text' class="form-control" id='datetimepicker4' /></div>

+1

the @sibsfinx fix never get to be merged, any reason?

Hello,
Can anyone help me with a integration problem?
i've created a fiddle with my code so far.
My problem is the datetime picker gets cut by the table.

Thanks

@fredericoregateiro this is exactly the issue we are all talking about here and have offered many different solutions to. The most "correct" solution for your needs depends on many different factors as well as what you may or may not be willing to implement.

The immediate solution that comes to mind requires overriding jsgrid's styles, which to me is anathema unless absolutely necessary...
https://jsfiddle.net/8hLbskq3/

otherwise you can try various widgetParent solutions (specifically, body in this case) as per https://jsfiddle.net/1de9tuqm/

@epimeth thanks, i just took a quick look and its seems working fine

If I use overflow: visible (it is a common fix of this problem) then scrollbar disappears. But my table has scrollbars and I need bootstrap datepicker to appear over it. Any suggestions here?

Been using one of the widgetParent solutions. Note that on resize event the widget position is recalculated so adjusting at dp.show event is not sufficient. For example, on Android 7 tablet if the field gets focus and keyboard appears, the widget will be placed at wrong position. So you'll have to adjust the position at private place() event or add a listener to resize event.

Try this solution, it is working for me

                     var datepicker = sandbox.dom('body').find('.bootstrap-datetimepicker-widget:last'),
                position = datepicker.offset();

            // Move datepicker to the exact same place it was but attached to body
            datepicker.appendTo('body');
            datepicker.css({
                position: 'absolute',
                top: position.top,
                bottom: 'auto',
                left: position.left,
                right: 'auto'
            });

@Paulmicha solution worked for me as well 馃憤

Setting parent position to relative works for me inside table
Thanks to @simondubois !

Hello. Thanks for using my project. We鈥檙e closing all tickets/prs for v4 as it is no longer supported. We鈥檙e making way for a new version. Please read this blog post

Was this page helpful?
0 / 5 - 0 ratings

Related issues

miraclebg picture miraclebg  路  3Comments

gouthamgit picture gouthamgit  路  4Comments

malhayek2014 picture malhayek2014  路  4Comments

benbhale picture benbhale  路  5Comments

y2kim picture y2kim  路  5Comments