JQuery UI datepicker next and prev buttons only have one ancestor. $(e.target).parents() only returns one element

StackOverflow https://stackoverflow.com/questions/22406505

Question

I don't have enough rep to post my own answer just yet, but here it is before I waste more peoples' time:

Ok, I now understand why I don't get all of the expected ancestors:

JQuery datepicker deletes the parent node (the datepicker-head) onclick. After that my event is triggered on the button of the element that already got deleted. So now I am "trapped" in the scope of the deleted element and can only traverse up to the deleted container itself. I think I can work out a solution for my event-delegation with this knowledge!

I will add this as the proper answer to my problem in 8 hours! ;)

The original question/problem: I've already thoroughly searched stackoverflow, google etc. for this problem and can't seem to find a solution.

I am going crazy over this problem: I have a JQuery UI Datepicker in a container that hides if you click outside of it. That means I need to know when there is interaction inside the container so it does not get closed! On document.click I am traversing up from the given element to find my enclosing container (or meet any other condition) to either allow the action, or deny it. This works like a charm - also clicks onto the generated datepicker work, except for the 'next month' and 'previous month' buttons. In the following fiddle I am logging the .parents() of the clicked element. Note that if you click the next and prev buttons the document.click will go through, closing the container and the log will only show the immediate parent of the buttons. If you click other elements in the datepicker you will see that the .parents() will give you all elements up to the enclosing html-tag.

Does anyone have any idea of how to fix this?

I made a simple example to showcase this... Here is the html:

<div class="container">
    <input type="text" class="myToggleInput" />
    <div class="toggleContainer" style="display: none">
        <div class="myDatepicker"></div>
    </div>
</div>

This is the script:

$(document).ready(
    init()
);

function init() {
    $('.myDatepicker').datepicker();
    $(document).on('click', '.myToggleInput', function(e) {
        $('.toggleContainer').show();
    });

    $(document).on('click', function(e) {
        //Logging the targets parents
        //Note that the next and prev buttons only go up one level in the DOM Tree, thus
        //not returning all of their parents...
        console.log($(e.target).parents());
        if ($(e.target).parents('.toggleContainer').length == 0 && !$(e.target).hasClass('myToggleInput')) {
            $('.toggleContainer').hide();
        }
    });
};

Here is the fiddle: http://jsfiddle.net/Px9Ab/

To clarify: Yes, I could add the classes of the next/prev buttons to my conditions, but I'd rather like a general solution, so I can be sure that '$(e.target).parents()' always traverses up to the html-node.

Why I can't use stoppropagation: There is a lot of dynamic stuff going on inside this container and the rest of the website. So for example I am reloading a list of elements dependent on the chosen date, which also have events attached to them, or rather delegate up to document as well. That's why I can't stop propagation on the container.

Any other solutions that completely circumvent my issue are welcome too! :)

Était-ce utile?

La solution

JQuery datepicker deletes the parent node (the datepicker-head) onclick. After that my event is triggered on the button of the element that already got deleted. So now I am "trapped" in the scope of the deleted element and can only traverse up to the deleted container itself.

To circumvent my original problem I had to filter out all the clickable elements that do not bubble up.

Eg:

$(document).on('click', function(e) {
    if (!$(e.target).hasClass('ui-dialog')) {
        window.XYZ.hideAllDatePickersPseudoMethod();
    }
});

I know that's more some kind of a workaround than a fix for the problem, but it's the only solution I came up with that suits all my needs.

Autres conseils

Just stop event propagation for any click events triggered on the .toggleContainer element:

$('.toggleContainer').on('click', function(e) {
   e.stopPropagation(); 
});

$(document).on('click', function(e) {
    $('.toggleContainer').hide();
});

jsFiddle demo

Use event.stopPropagation on input and .toggleContainer and datepicker navigational:

$('.myDatepicker').datepicker();

$(document).on("click", '.myToggleInput', function () {
    $('.toggleContainer').show();
});
$(document).on("click", function () {
   $('.toggleContainer').hide();
});
$(document).on("click", ".toggleContainer, .myToggleInput, .ui-datepicker-next, .ui-datepicker-prev", function (e) {
    e.stopPropagation();
});

http://jsfiddle.net/Px9Ab/5/

$('.myDatepicker').datepicker();

$(document).on("click", '.myToggleInput', function () {
    $('.toggleContainer').toggle();
});
$(document).on("click", function () {
   $('.toggleContainer').toggle();
});
$(document).on("click", ".toggleContainer, .myToggleInput, .ui-datepicker-next, .ui-   datepicker-prev", function (e) {
    e.stopPropagation();
});
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top