3

I have a datepicker input and a timepicker input that I'd like to use to schedule a person for appointments.

When the user clicks on the input to open the datepicker menu, I'd like to grey out specific datetimes. I've got a php function that returns this array of datetimes in in 'Y-m-d H:i:s' string format. But I dont' know how to use that function's return value to give the javascript function what it needs to disable a range of dates in datepicker.

In the onSelect event of my datepicker, I want it to enable/disable time options in my timepicker according to which timeslots are booked for that day. But I don't know how.

  1. Datepicker uses beforeshowDay: to disable booked dates

  2. user selects date from datepicker

  3. Datepicker enables/disables times in the timepicker

I did find out how to disable timeranges in the timepicker Here. the code example is this:

$('input.timepicker').timepicker({
    'disableTimeRanges': [
        ['1am', '2am'],
        ['3am', '4:01am']
    ]
});

But that's how I'd disable the time ranges from within the scope of the timepicker. I don't know how to disable them from BeforeShowDay in datepicker?

<script type="text/javascript">   
    $(document).ready(function(){
        $( "#datepickerListAppointments" ).datepicker(
        {
            minDate:'0',
            beforeShowDay:
            function(dt)
            {   // need to disable days other than tuesday and wednesday too.
                return [dt.getDay() === 2 || dt.getDay() === 3, ""];
            },
            onSelect : function(){
                should disable/enable timepicker times from here?
            }
        });

        $('input.timepicker').timepicker({
            timeFormat: 'h:mm p',
            interval: 90,
            minTime: '9',
            maxTime: '10:30am',
            defaultTime: '9',
            startTime: '9:00',
            dynamic: false,
            dropdown: true,
            scrollbar: false                
        });

    });

This is the function that gives the datetimes, in case it helps to know.

function get_next_open_appointments($numAppointments, $timeSlotToExclude = "")
{
    global $db;
    $whereCondition = "WHERE FirstName = :null ";
    if ($timeSlotToExclude != "")
    {
        $whereCondition .= "AND AppointmentTime != '$timeSlotToExclude' ";
    }

    $query = "SELECT DISTINCT AppointmentTime FROM appointments
              $whereCondition
              ORDER BY AppointmentTime ASC LIMIT $numAppointments";
    $statement = $db->prepare($query);
    $statement->bindValue(':null', "");
    $statement->execute();
    $datesArray = array();
    while ($row = $statement->fetch()) 
    {
        array_push($datesArray, $row['AppointmentTime']);
    }
    $statement->closeCursor();
    return $datesArray;
}

UPDATE:

Hugo De Carmo pointed me in the right direction and I got the dates to disable/enable appropriately. However, I don't know how to use the datetimes that I pulled in code below to disable/enable times in the timepicker.

Here is the new code:

<script type="text/javascript">   
    $(document).ready(function(){

        // uses php to get open appointments, and put them in a javascript array
        <?php $datetime_openings = get_next_open_appointments(200);
        $date_openings = array();
        foreach ($datetime_openings as $dt)
        {
            array_push($date_openings, substr($dt,0,10)); // just the date part
        }

        $json_date_openings = json_encode($date_openings);
        echo "var arr_Openings = ". $json_date_openings . ";\n";
        ?>

        $( "#datepickerOpenAppointments" ).datepicker(
        {
            minDate:'0',
            beforeShowDay:
            function(dt)
            {
                var string = jQuery.datepicker.formatDate('yy-mm-dd', dt);
                var bFound = (arr_Openings.indexOf(string) != -1);
                return [ bFound ]; 
            },
            onSelect : function(){
               //    Should disable/enable time ranges here?
        });

        $('input.timepicker').timepicker({
            timeFormat: 'h:mm p',
            interval: 90,
            minTime: '9',
            maxTime: '10:30am',
            defaultTime: '9',
            startTime: '9:00',
            dynamic: false,
            dropdown: true,
            scrollbar: false                
        });

    });
ArmorCode
  • 739
  • 4
  • 15
  • 33

3 Answers3

4

Try this,
sorry i didn't use beforeshowDay
select date 2017-7-14 and 2017-7-17 and see

var disabledDateTime = {
  '2017-7-14':[
   ['2:30am','3:00am'],
    ['6:30am','9:00am']
  ],
 '2017-7-17':[
   ['1:00am','3:00am'],
    ['5:30am','7:00am'],
    ['11:30am','2:00pm']
  ]
};

$(function() {
  $('#pickTime').timepicker();
  $('#pickDate').datepicker({
    'format': 'yyyy-m-d',
    'autoclose': true
  }).on('changeDate',function(e){
    var ts = new Date(e.date);
    var m = ts.getMonth()+1;
    var dt = ts.getFullYear() + '-' + m + '-' + ts.getDate();
    var opt = {'disableTimeRanges': []}
    if(typeof(disabledDateTime[dt])!='undefined'){
      $('#pickTime').timepicker('setTime', '');
      opt = {'disableTimeRanges': disabledDateTime[dt]}
    }
    $('#pickTime').timepicker('option',opt);
  });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

<link href="https://jonthornton.github.io/jquery-timepicker/lib/bootstrap-datepicker.css" rel="stylesheet"/>
<script src="https://jonthornton.github.io/jquery-timepicker/lib/bootstrap-datepicker.js"></script>
<link href="https://jonthornton.github.io/jquery-timepicker/jquery.timepicker.css" rel="stylesheet"/>
<script src="https://jonthornton.github.io/jquery-timepicker/jquery.timepicker.js"></script>

<input id="pickDate" type="text" class="date" />
<input id="pickTime" type="text" class="time" />
Atmahadli
  • 687
  • 8
  • 14
  • var disabledDateTime = { '2017-7-14':[ ['2:30am','3:00am'], ['6:30am','9:00am'] ], '2017-7-17':[ ['1:00am','3:00am'], ['5:30am','7:00am'], ['11:30am','2:00pm'] ] }; But i want to display this dynamically from db values such as date,starttime,endtime using php.how can i do this? – heart hacker Dec 18 '17 at 06:15
  • var disabledDateTime = {'2017-7-14':[['2:30am','3:00am'],['6:30am','9:00am']], '2017-7-17':[['1:00am','3:00am'],['5:30am','2:00pm']]}; the above javascript storing two values into a variable(disabledDateTime) but i want to store dynamically values into that variable(disabledDateTime) using php from database – heart hacker Dec 18 '17 at 06:40
  • @hearthacker you can use ajax to retrieve the data(json) and set var disabledDateTime at any times. – Atmahadli Dec 29 '17 at 17:00
3

Someone already answered this question here.

Anyway, the following code should give you an insight on how to solve the problem.

// supose your script return a json similar to the following
{
    "data": [
        // ...
        "17-07-11"
    ]
}

$(function() {
  $.getJSON("/path/to/script", function(response){
    $('#datepickerListAppointments').datepicker({
      beforeShowDay: function(dt) {
        var config = [];
        config[1] = 'class';

        if ((dt.getDay() === 2) || (dt.getDay() === 3)) {
          config[0] = false;
          return config;
        }

        var string = jQuery.datepicker.formatDate('yy-mm-dd', dt);
        config[0] = (response.data.indexOf(string) === -1);
        return config;
      }
    });
  });
});

I've assumed that you're exchanging data with the server using some kind of API, hence the use of getJSON, if you want to handle server errors then I suggest you to use ajax combining with Promise.

Edit 1

You can extract everything from your date using the class DateTime, here is a snippet:

$openings = array();

$date = DateTime::createFromFormat("y/m/d H:i", "17/07/15 08:30");

if (!isset($openings[$date->format("y-m-d")])) {
    $openings[$date->format("y-m-d")] = array();
}

$openings[$date->format("y-m-d")][] = array(
    "hour" => $date->format("Ha"),
    "minute" => $date->format("i")
);

/* result
array(1) {
  ["17-07-15"]=>
  array(1) {
    [0]=>
    array(2) {
      ["hour"]=>
      string(4) "08am"
      ["minute"]=>
      string(2) "30"
    }
  }
}
*/

Then you can disable the time in timepicker based on date, you'll probably need to register a callback function in your datepicker to update the timepicker based on the chosen date or you'll have to override the timepicker with new settings.

Hugo do Carmo
  • 179
  • 1
  • 10
1

Yes, you can dinamically update timepicker disableTimeRanges inside the onSelect function using the option method of the timepicker component.

I'm supposing that:

  • You are using jQuery UI datepicker (since you didn't tag your question with twitter-bootstrap and bootstrap-datepicker has no minDate option)
  • You are using the first version of get_next_open_appointments that returns an array of datetimes (like ['2017-07-25 09:30:00', ...] see fakeDisabledTimes in the snippet)

I'm using momentjs in order to simplify dates managment. In the following code, I've used moment parsing functions (moment(String) and moment(String, String)), isSame, add and format. Note that moment tokens are different from PHP tokens.

Here a complete working sample:

var fakeDisabledTimes = [
  '2017-07-25 09:30:00', '2017-07-26 10:00:00',
  '2017-08-01 09:00:00', '2017-08-02 09:30:00',
  '2017-08-08 10:30:00', '2017-08-09 10:00:00',
  '2017-07-15 09:30:00', '2017-07-16 10:00:00'
];

$(document).ready(function(){
  $( "#datepickerListAppointments" ).datepicker({
    minDate:'0',
    beforeShowDay:
    function(dt){
      // need to disable days other than tuesday and wednesday too.
      return [dt.getDay() === 2 || dt.getDay() === 3, ""];
    },
    onSelect : function(dateText){
      //should disable/enable timepicker times from here!
      // parse selected date into moment object
      var selDate = moment(dateText, 'MM/DD/YYYY');
      // init array of disabled times
      var disabledTimes = [];
      // for each appoinment returned by the server
      for(var i=0; i<fakeDisabledTimes.length; i++){
        // parse appoinment datetime into moment object
        var m = moment(fakeDisabledTimes[i]);
        // check if appointment is in the selected day
        if( selDate.isSame(m, 'day') ){
          // create a 30 minutes range of disabled time
          var entry = [
            m.format('h:mm a'),
            m.clone().add(30, 'm').format('h:mm a')
          ];
          // add the range to disabled times array
          disabledTimes.push(entry);
        }
      }
      // dinamically update disableTimeRanges option
      $('input.timepicker').timepicker('option', 'disableTimeRanges', disabledTimes);
    }
  });

  $('input.timepicker').timepicker({
    timeFormat: 'h:i a',
    interval: 90,
    minTime: '9',
    maxTime: '10:30am',
    defaultTime: '9',
    startTime: '9:00',
    dynamic: false,
    dropdown: true,
    scrollbar: false                
  });

});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.1/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.11.4/jquery-ui.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-timepicker/1.10.0/jquery.timepicker.js"></script>

<link href="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.11.4/jquery-ui.css" rel="stylesheet"/>
<link href="https://cdnjs.cloudflare.com/ajax/libs/jquery-timepicker/1.10.0/jquery.timepicker.css" rel="stylesheet"/>

<input id="datepickerListAppointments" type="text">
<input class="timepicker" type="text">
VincenzoC
  • 30,117
  • 12
  • 90
  • 112