Как привязать jQuery Datepicker после обновления Ajax?

#javascript #jquery #ajax #jquery-ui

#jquery #ajax #datepicker #jquery-события

Вопрос:

У меня есть jQuery datepicker, который отлично работает для меня, за исключением того, что когда я обновляю содержимое через ajax, я теряю datepicker. Из того, что я могу сказать, я должен использовать jQuery on() для привязки его к входным данным, но, похоже, я не могу найти подходящее событие для его привязки.

Работает в первый раз, но не при последующих обновлениях:

 $("[id^=startPicker]").datetimepicker({
        showOn: "button",
        buttonImage: "/img/calendar_icon.png",
        buttonImageOnly: true,
        dateFormat: 'mm/dd/yy',
        timeFormat: 'hh:mm tt',
        stepMinute: 1,
        onClose: function (dateText, inst) {

            var selectedDate = $(this).datepicker("getDate"); //Date object

            $.ajax({
                url: "/url",
                dataType: "json",
                method: 'post',
                data: {
                    value: selectedDate.toDateString()   ' '   selectedDate.toTimeString()
                },
                beforeSend: function () {
                    $("#loading").fadeIn();
                },
                success: function (data, textStatus) {
                    $("#content").html(data);
                },
                complete: function () {
                    $("#loading").fadeOut();
                }
            });
        }
    });
  

Не привязывается в первый раз или при последующих обновлениях:

 $('#content').on('ready', "[id^=startPicker]", function () {
        $(this).datetimepicker({
            showOn: "button",
            buttonImage: "/img/calendar_icon.png",
            buttonImageOnly: true,
            dateFormat: 'mm/dd/yy',
            timeFormat: 'hh:mm tt',
            stepMinute: 1,
            onClose: function (dateText, inst) {
    
                var selectedDate = $(this).datepicker("getDate"); //Date object
    
                $.ajax({
                    url: "/url",
                    dataType: "json",
                    method: 'post',
                    data: {
                        value: selectedDate.toDateString()   ' '   selectedDate.toTimeString()
                    },
                    beforeSend: function () {
                        $("#loading").fadeIn();
                    },
                    success: function (data, textStatus) {
                        $("#content").html(data);
                    },
                    complete: function () {
                        $("#loading").fadeOut();
                    }
                });
            }
        });
    });
  

Комментарии:

1. Вы не можете делегировать этот плагин с .on() помощью события из коробки. Вам нужно будет повторно создать экземпляр плагина для элементов в .success() обратном вызове.

2. готовое событие используется только в документе, даже если вы можете привязать его к любым другим элементам. Но при использовании синтаксиса .on() это не будет запущено после завершения события ready, в отличие от использования псевдонима $().ready()

Ответ №1:

Функция jQuery .on() предназначена для отложенной обработки событий, но она не работает для инициализации плагина.

Это работает для событий, потому что модель DOM распространяет события от элементов DOM к их родительским элементам вплоть до вершины. Итак, когда вы нажимаете на ссылку, вы также нажимаете на все, что содержит эту ссылку ( div например, a), на все, что содержит этот контейнер, и так далее вплоть до body тега и, в конечном итоге document , самого тега. .on() использует это преимущество путем привязки к событию click общего родительского элемента вместо динамических дочерних элементов, поэтому дочерние элементы могут быть добавлены / удалены без потери обработчика событий на родительском элементе.

Однако инициализация плагина таким образом не работает. Чтобы инициализировать плагин для целевого элемента, это должно быть сделано для самого элемента, что означает, что элемент должен находиться в DOM в данный момент. Таким образом, когда вы добавляете новые элементы динамически, вам нужно настроить таргетинг на эти новые элементы и инициализировать плагин для них. Таким образом, ваша success функция из вызова AJAX должна была бы это сделать.

Обратите внимание, что, поскольку ваш вызов AJAX сам находится внутри вашей инициализации, вам нужно будет разделить некоторые из них на отдельные функции для повторного использования. В противном случае эта повторная инициализация будет гнездиться внутри себя бесконечно.

Может быть, что-то вроде этого:

 var datePickerClose = function (dateText, inst) {

    var selectedDate = $(this).datepicker("getDate"); //Date object

    $.ajax({
        url: "/url",
        dataType: "json",
        method: 'post',
        data: {
            value: selectedDate.toDateString()   ' '   selectedDate.toTimeString()
        },
        beforeSend: function () {
            $("#loading").fadeIn();
        },
        success: function (data, textStatus) {
            $("#content").html(data);
            $("#content").find("[id^=startPicker]").each(function () {
                bindDatePicker(this);
            });
        },
        complete: function () {
            $("#loading").fadeOut();
        }
    });
};

var bindDatePicker = function(element) {
    $(element).datetimepicker({
        showOn: "button",
        buttonImage: "/img/calendar_icon.png",
        buttonImageOnly: true,
        dateFormat: 'mm/dd/yy',
        timeFormat: 'hh:mm tt',
        stepMinute: 1,
        onClose: datePickerClose
    });
};

$("[id^=startPicker]").each(function() {
    bindDatePicker(this);
});
  

Это, конечно, бесплатный непроверенный код, просто для демонстрации концепции. Это может потребовать небольшой настройки, и может быть более элегантный способ выполнить ту же логику.

Комментарии:

1. Спасибо за подробный ответ! Я почти на месте!

2. Спасибо за подробный ответ! Я почти на месте! $("[id^=startPicker]").each(function() { bindDatePicker(this); }); отлично работает для привязки при загрузке страницы, но: $("#content").find("[id^=startPicker]").each(function () { bindDatePicker(this); }); похоже, не выполняется, по крайней мере, согласно firefox ddebugger. Я также пытался успешно вызвать его из других функций ajax и получить то же самое.

3. @richj: Успешно ли возвращается вызов AJAX? Если success вызывается обработчик, то он должен достигать этой строки кода.

4. Похоже, что, несмотря на то, что функция работает, т. Е. Дата обновляется, возвращается HTML-код страницы и ошибок нет, обработчик успеха не запускается. Я даже пытался добавить простое оповещение об успехе, чтобы протестировать его, но безрезультатно. Как мне проверить результат вызова ajax? Firefox говорит: «ПОЛУЧИТЬ URL … 200 OK’

5. Я переместил привязку к полному обработчику, и он работает, но я предполагаю, что использовать полный обработчик для этой функции — плохой тон?

Ответ №2:

Вы не можете делегировать плагин, делегирование предназначено только для прослушивателя событий. Используйте функцию обратного вызова успеха и повторно активируйте плагин datepicker после добавления целевого элемента

 success: function (data, textStatus) {
    $("#content").html(data).find('[id^=startPicker]').datepicker({...});
},
  

Ответ №3:

У меня похожая проблема: после перезагрузки страницы ajax я не могу установить новый datepicker с помощью $(element).datepicker() . Поскольку Datepicker выполняет только одну чистую инициализацию, я просто устанавливаю сразу после успеха ajax:

 $.datepicker.initialized = false;
  

Теперь следующий $ (элемент).datepicker() вызовет новую инициализацию. Это влияет на все datepicker на стороне, поэтому вы, возможно, сбросили datpicker за пределами ajax-контейнера.

Ответ №4:

На самом деле, самый простой способ, который я нашел для этого, — просто поместить код привязки в функцию успеха следующим образом: ELEMENT.datepicker(); .

Например: $('.datepicker').datepicker();

Полный код:

 $('#loaddetails').on('click',function(){
                //Run ajax fetch here
                    $.ajax({
                       type: "POST",
                       url: "yourlink",
                       data: $('form').serialize(), // serializes the form's elements.
                       dataType: 'json',
                       beforeSend: function () {
                         console.log('Form serialised');
                         $('#status').html('<img src="../img/spinner.gif" width="16" height="16">');
                         },
                       success: function(data)
                       {
                        $('#status').html(data);
                        $('.datepicker').datepicker();
                          },
                          error: function (xhr, ajaxOptions, thrownError) {
                            alert(xhr.status);
                            alert(thrownError);
                          }
                     });
                console.log("All ok");
                return false;
            });
  

Ответ №5:

если вы работаете с datetimepicker, используйте это: $(«#datetimepicker1»).datetimepicker(«уничтожить»); оператор перед вызовом ajax, чтобы удалить существующий экземпляр datetimepicker . Он отобразит новый экземпляр datetimepicker, который отлично работает без обновления или перезагрузки окна. Смотрите полный код:

 $("#datetimepicker1").datetimepicker("destroy"); // add this line before ajax call
    $.ajax({
        type: type,
        url: ajaxurl,
        data: formdata,
        dataType: 'json',
        success: function (data) {
            $('#datetimepicker1').datetimepicker({
                daysOfWeekDisabled: [0], 
                format: 'L',
                format: 'DD/MM/YYYY',
            });
        },
        error: function (data) {
            console.log(data);
        }
    });