Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dependent date selectors using html selects and dates to make sense

I Am trying to build a custom START and END date selector, but unfortunatelly because of the design I won't be able to use the jquery UI Datepicker, so I am stucked with the old fashionate of splitting the dates in 3 <select>s

In order to keep this feature usable, we find this -at least- complicated parts:

  • Let days make sense with each month (Dont want 31 of feb selectable , ..)
  • Set next thay from START to the END selector

So I thought better to delegate the date calculation to the javascript Date() object so at least I can abstrat that part.

I am almost there,

But some how the Date() object tell the right date, but both selectors show each set of Days for the previous one (For example, top 28 days happen in March instead of FEB)

    $(function(){

months = ['jan','feb','mar','apr','may','jun','jul','ago','sep','oct','nov','dec'];
        /* Cachear selects */
        var $ld = $('select[name=llegada-dia]');
        var $lm = $('select[name=llegada-mes]');
        var $ly = $('select[name=llegada-ano]');
        var $sd = $('select[name=salida-dia]');
        var $sm = $('select[name=salida-mes]');
        var $sy = $('select[name=salida-ano]');
        var manyDays = function( month, year ){
            var fecha = new Date(year, (month) , 0);
            return fecha.getDate();
        }
        var paintCals = function( day, month , year ){
            if(day == '') day = 1;
            if(month == '') month = 0;
            if(year == '' ) year = 2013;
            //month = month -1;
            var fecha = new Date( year, month , day );          
            var dia = fecha.getDate();
            var mes = fecha.getMonth();
            var anyo = fecha.getFullYear();
            var dias_mes = manyDays( mes,anyo );
            /* Generate next date = fecha + 1 */
            var next_fecha = fecha;

            next_fecha.setDate(next_fecha.getDate() + 1); 
            next_fecha.setMonth(fecha.getMonth() + (dia == dias_mes ? 1 : 0)   ); 
            next_fecha.setFullYear(fecha.getFullYear() + (mes == 12 ? 1 : 0)  ); 

            var next_dia = next_fecha.getDate();
            var next_mes = next_fecha.getMonth();
            var next_anyo = next_fecha.getFullYear();
            var next_dias_mes = manyDays( next_mes, next_anyo ) ;
            $ld.empty();
            for(var tmpdia = 1; tmpdia <= dias_mes; tmpdia++){
                var doption = $('<option>').attr( 'value',tmpdia )
                                           .text( tmpdia );
                if(dia == tmpdia && dia != ''){
                    doption.attr('selected', 'selected');
                }
                $ld.append(doption);
            }
            /* Actualizar dias salida */
            $sd.empty();
            for(var tmpdia = next_dia; tmpdia <= next_dias_mes; tmpdia++){
                var doption = $('<option>').attr( 'value' , tmpdia )
                                           .text(tmpdia);
                if(next_dia == tmpdia && next_dia != ''){
                    doption.attr('selected', 'selected');
                }
                $sd.append(doption);
            }
            /* Actualizar meses salida */
            $sm.empty();
            for(var tmpmes = next_mes ; tmpmes < 12; tmpmes++){
                var doption = $('<option>').attr('value',tmpmes)
                                           .text(months[tmpmes]);
                if(dia == tmpdia && dia != ''){
                    doption.attr('selected', 'selected');
                }
                $sm.append(doption);
            }
            /* Actualizar anyos salida */
            $sy.empty();
            for(var tmpanyo = next_anyo; tmpanyo <= 2020; tmpanyo++){
                var doption = $('<option>').attr('value',tmpanyo)
                                           .text(tmpanyo);
                if(next_anyo == tmpanyo && next_anyo != ''){
                    doption.attr('selected', 'selected');
                }
                $sy.append(doption);
            }
        } 
        $('.arrival select').on('change',function(){
            var ldia = $ld.val();
            var lmes = $lm.val();
            var lano = $ly.val();
            var ldias = paintCals(ldia,lmes,lano);
        });
    })

And here it can be fiddled:

http://jsfiddle.net/96qyH/8/

Any idea what I'm missing here?

like image 494
Toni Michel Caubet Avatar asked Oct 17 '13 18:10

Toni Michel Caubet


2 Answers

First: manyDays fn needs to be:

var days_in_month = new Date(year, month+1, 0);

Because otherwise it goes back to previous month. You can read more about it in the comments of the most popular answer here: Get number days in a specified month using javascript?

Second: I removed

next_fecha.setMonth(fecha.getMonth() + (dia == dias_mes ? 1 : 0)   );

Since you already have

next_fecha.setDate(next_fecha.getDate()+1);

It switches month automatically in the end of month.

Third: this part had dia instead of month:

/* Actualizar meses salida */
        $sm.empty();
        for(var tmpmes = next_mes ; tmpmes < 12; tmpmes++){
    var doption = $('<option>').attr('value',tmpmes).text(months[tmpmes]);
            if(next_mes == tmpmes && next_mes != ''){
                console.log('fired');
      doption.attr('selected', 'selected');
            }
            $sm.append(doption);
        }

---- ADDED ----

Fourth: It also needs a check to see if Feb 31 exists. And if it is not, day should be the last day of that month. Otherwise the Date object didn't know what to do with the date and was giving wrong date.

Just needs to add a check:

var check_fecha = new Date( year, month );          
        check_mes = check_fecha.getMonth();
  check_anyo = check_fecha.getFullYear();
  var check_dias_mes = manyDays( check_mes, check_anyo );

  if(day > check_dias_mes)
    day = check_dias_mes;

Hope it solves it, check it out here: http://jsfiddle.net/96qyH/13/

like image 115
Nookeen Avatar answered Oct 30 '22 11:10

Nookeen


If source code is required

I have found some answers for you! That might help you out! :) I have created a plugin too, but you won't need it to be the only answer. So here is what would help you. If you want to have a look at the code, you can get the source code here: https://github.com/the-vs-organisation/vdatetimepicker

Solution to the first one

Let days make sense with each month (Dont want 31 of feb selectable , ..)

For this issue, I used the value from the list of month as:

var month = $('#monthval').attr('id');
if(month == "February") {
  // hide the last few list items..
}

And then so on. You can see the source code in my plugin. You will find out how to interact with the other months too.

You can use id of the container as its value, as we won't use select Because you cannot style the style attribute. So you will require a custom created datetimepicker.

Disabing any of the item in the list won't be a good idea for the UI, so you might need to hide it. Hiding it won't bother UI or user himself. As the item won't be available he won't have to worry about the thing.

Second one

I am not sure what you wanted in this one, so I will leave it instead of giving a vague answer.

My Assumptions

If you want to get the time remaining or if you want to compare them, then you can use this:

var time = "some_string_of_time";
var curTime = new Date();
// now time to get the seconds between it..
var seconds = Math.floor((curTime - Time) / (1000));
// now write them..
if (seconds > 0 && seconds < 60) {// seconds..
    $('element') = seconds + " seconds ago";
}

Hiding the values

But some how the Date() object tell the right date, but both selectors show each set of Days for the previous one (For example, top 28 days happen in March instead of FEB)

This can be minimized in select as well as in my code. All you need to use is a simple class or id and on the click event for the month selector. Hide the excessive list items if any. Otherwise show. In my plugin, January and December will always have 31 days, Feb will have 28. It all depends on the list item selected in the Month dropdown. You can update the code in other div using jQuery.

If you don't care about UI

If you don't want to style the UI, have you tried using the input tool?

<input type="date" name="datetime" />

This is a browser generated one. You can always use it when nothing else gets into handy.

How to access data from my plugin.

You can always try to get the data from the .vdtpckr once you have the fields filled by using their ID for example:

var month = $('.vmonthval').attr('id');

This way, you can get the values from this.

If you need any thing more, comment below! :) Also try to check out the source code from github. You will get many ideas from the code.

like image 23
Afzaal Ahmad Zeeshan Avatar answered Oct 30 '22 09:10

Afzaal Ahmad Zeeshan