Bootstrap-datepicker: datedDisabled on changeMonth and on show not working

Created on 29 Jun 2016  路  5Comments  路  Source: uxsolutions/bootstrap-datepicker

Expected behaviour

I want to disable date via loading by ajax. When datepicker onpens and month changed it must setDisabledDates from loaded array

Actual behaviour

I tryed set it by show and changeMonth event, but i did't find any example how to make it.
Please help me to solve this problem

Datepicker version used

v1.7.0-dev

Example code

var array = new Array();

    function load_reservation(stock, year = null, month = null, callback){
        jQuery.ajax({
            method: "POST",
            url: "'.Url::to(['site/ajax-load-reservation']).'",
            data: { "stock": stock, "year": year, "month": month },
            success: function(data) {
                if(data.result==1){
                    callback(data.array);                
                }
                else callback(null);
            },
            dataType: "json",
            async: false
        });


    }

    $(".book").each(function(){
        var id = $(this).attr("data-stock_id");
        load_reservation(id, null, null, function(result){
            array[id] = result;
            console.log("Loaded dates for #"+ id +": "+array[id]);
        });
    });

    $(".book").datepicker({
        multidate: true,
        startDate: "1d",
        language: "ru",
        format: "yyyy-mm-dd",
    }).on("click", function(e){
        var id = $(this).attr("data-stock_id");
        e.datesDisabled = array[id];
    }).on("changeMonth", function(e) {
        var id = $(this).attr("data-stock_id");
        var year = e.date.getFullYear();
        var month = e.date.getMonth() + 1;
        load_reservation(id, year, month, function(result){
            array[id] = result;
            console.log("Onchange Loaded dates for #"+ id +": "+array[id]);
        });  
        setDatesDisabled = array[id];
        console.log(e);
        return e;
    });

Jsfiddle example to reproduce the problem.

question

All 5 comments

Questions like this one should go to stackoverflow. But to push you in the right direction. There seems to be an async issue. setDatesDisabled = array[id]; runs before your callback. Also you are not calling setDatesDisabled method but just setting a global setDatesDisabled var.

I think this one can be closed.

I'm not sure there is any implementation we could do in our side for ajax loading.
There's a snippet that should works well in your case:

    <style>
        body div.datepicker td.disabled {
            background: #ab4646;
            color: #e47c7e;
            border-radius: 0;
        }

        body div.datepicker[data-state="loading"] div.datepicker-days::before {
            content:'';
            display: block;
            position: absolute;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            background: rgba(158, 158, 158, 0.35);
        }

        body div.datepicker[data-state="loading"] div.datepicker-days::after {
            content:'';
            display: block;
            position: absolute;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            background: no-repeat center center url(http://www.e-tlf.com/wp-content/plugins/nice-login-register-widget/images/loading_transparent.gif);
        }
    </style>
<input class="booking-picker">
<script>
    $(document).ready(function () {

        // We isolate varaible for each picker
        $('.booking-picker').each(function () {
            var input, picker, xhr, token,
                    selected_date, last_selected_date, dates,
                    timetowait;

            xhr = null;
            token = null;
            input = $(this);
            timetowait = 300;
            selected_date = new Date();
            last_selected_date = null;

            // Load the dates
            function loadDates(c_token) {
                // If the token don't match we don't make the call
                // This allow to avoid call spaming
                if (c_token !== token) {
                    return;
                }
                picker.attr('data-state', 'loading');

                // Replace by $.ajax
                fakeAjaxCall({
                    url: '/booking',
                    data: {
                        date: selected_date
                    }
                }, function (data) {
                    last_selected_date = selected_date;
                    picker.attr('data-state', 'loaded');
                    dates = data;
                    input.datepicker('setDatesDisabled', data);
                });
            }

            // When we change month we change the stored date
            input.on('changeMonth', function (event) {
                selected_date = event.date;
            });

            // When show is trigerred we load the dates
            input.on('show', function (event) {
                // Only get the picker once
                if (picker === undefined) {
                    picker = $(this).data().datepicker.picker;
                    picker.attr('data-state', '');
                }
                // If we actually didn't change month we don't go further
                if (last_selected_date === selected_date) {
                    return;
                }
                // Abort any request ongoing
                if (xhr !== null && typeof xhr.abort === 'function') {
                    xhr.abort();
                }
                var new_token = new Date();
                token = new_token;
                setTimeout(function () {
                    loadDates(new_token);
                }, timetowait);
            });

            input.datepicker({
                format: 'yyyy-mm-dd',
                updateViewDate: false,
                beforeShowDay: function (date) {
                    // Always disable days out of the month if you only want to load shown month
                    // Else you'll have to load past and next month as well as current month
                    return date.getMonth() === selected_date.getMonth();
                }
            });
        });
    });

    // Fake ajax call that will generate 4 to 15 disabled dates
    window.fakeAjaxCall = function (options, callback) {
        setTimeout(function () {
            var i, j, y, m, d, dates = [];
            y = options.data.date.getUTCFullYear();
            m = options.data.date.getMonth() + 1;
            j = Math.random() * (15 - 4) + 4;

            for (i = 0; i < j; i += 1) {
                d = Math.floor(Math.random() * (new Date(y, m + 1, 0).getDate() - 1) + 1);
                dates.push([y, m, d].join('-'));
            }
            callback(dates);
        }, (Math.random() * (20 - 3) + 3) * 100);
    }
</script>

Thank you for the example! I'm trying to achieve same behavior and having strange side effect of date jumping back to "today" after month is changed. Here I have converted your example into jsfiddle http://jsfiddle.net/Algis78/5x9e9ex4/ to demonstrate what I mean. Where did I go wrong?

@asarapas What you are facing is a known and confirmed bug in bootstrap-datepicker: #2054 You could avoid the bug if you set updateViewDate option to false or write a work-a-round that updates viewDate by using private api (#1978) after you called setDatesDisabled.

Of course you could also write an PR that fixes the bug in bootstrap-datepicker. :-)

After looking at the source code realized that updateViewDate option is available in v1.7.0-RCx. Updated Fiddle to reference latest RC version and everything works as expected. Thank you.

Was this page helpful?
0 / 5 - 0 ratings