Timepicker fields disappear when you select many dates

Asked

Viewed 342 times

7

I’m creating an app with dynamic calendar creation.

My application uses:

  • Bootstrap 3
  • jQuery 1.11.0
  • jQuery-ui 1.10.3
  • jQuery Timepicker Addon 1.5.0

I create a calendar on the page (jQuery UI Datepicker), when the person selects the date I create a dynamic field for selecting hours (start and end periods) on that day that can be added.

HTML

<div class="form-group">
    <label for="datas_sel" class="control-label">Datas do evento</label><br>
    <div id="datas_sel" style="float:left;"></div><br class="clear">&nbsp;<br>
    <label>Horas para as datas selecionadas:</label><br>
    <div id="horas_sel" style="width:100%;"></div><br class="clear">&nbsp;<br>
</div>

Javascript

//classe de implementação
var calendario = {
    datas : new Array(),
    padNumero: function(num) {
        return (num.toString().length == 1)?"0"+num.toString():num.toString();
    },
    forDate : function(str){
        return str.substring(6) + "/" + str.substring(4,6) + "/" + str.substring(0,4);
    },
    sorteio: function(a, b) {
        return a.getAttribute('data-date') - b.getAttribute('data-date');
    },
    dataOrganiza: function(){
        var organizar = $("#horas_sel div").toArray().sort(this.sorteio);
        $("#horas_sel div").remove();
        $.each(organizar, function (k, v) {
            $('#horas_sel').append(v);
        });
    },
    addRemData: function(data) {
        var index = jQuery.inArray(data, this.datas);
        if (index >= 0){
            this.removeDate(index);
        }else{
            this.addDate(data);
        }
        this.dataOrganiza();
    },
    addDate: function(data) {
        if (jQuery.inArray(data, this.datas) < 0){
            this.datas.push(data);
        }
        $('#horas_sel').append('<div id="dia_'+data+'" data-date="'+data+'" data-horas="0">\
<span id="data_'+data+'"><b>'+this.forDate(data)+':</b></span>\
<span id="hora_'+data+'"></span>\
<span id="plusicon_'+data+'" class="glyphicon glyphicon-plus-sign" style="padding:3px;border-left:1px solid #CCC;"></span>\
</div>');
        setTimeout(function(){
            $('#plusicon_'+data).click(function(){
                calendario.addHora(data)
            });
            calendario.addHora(data);
        },300);
    },
    removeDate: function(ind) {
        var d = this.datas.splice(ind, 1);
        $('#dia_'+d).remove();
    },
    addHora: function(data){
        var num = $('#dia_'+data).attr('data-horas');
        num = (parseInt(num)>=0)? parseInt(num)+1:1;
        $('#dia_'+data).attr('data-horas',num);
        $('#hora_'+data).append('<span id="ttem_'+data+'_'+num+'">\
Inicio: <input type="text" id="tini_'+data+'_'+num+'" class="form-control" placeholder="12:00"/> \
Final:  <input type="text" id="tfim_'+data+'_'+num+'" class="form-control" placeholder="13:00"/>\
<span id="tmen_'+data+'_'+num+'" class="glyphicon glyphicon-minus-sign" style="margin-right:10px; padding:3px; border-right:1px solid #ccc;"></span>\
</span>');
        if($('#hora_'+data+' input').length >= 6){
            $('#plusicon_'+data).css('display', 'none');
        }else{
            $('#plusicon_'+data).css('display', 'inline-block');
        }
        setTimeout(function(){
            $('#tini_'+data+'_'+num+', #tfim_'+data+'_'+num).timepicker({stepMinute: 5});
            $('#tmen_'+data+'_'+num).click(function(){
                calendario.remHora(data,num);
            });
        },300);
    },
    remHora: function(data, id){
        $('#ttem_'+data+'_'+id).remove();
        if($('#hora_'+data+' input').length >= 8){
            $('#plusicon_'+data).css('display', 'none');
        }else{
            $('#plusicon_'+data).css('display', 'inline-block');
        }
    }
}
//inicia o calendário
$('#datas_sel').datepicker({
    numberOfMonths: [1,3],
    howWeek: true,
    weekHeader: "W",
    onSelect: function (dateText, inst) {
        calendario.addRemData(dateText.split('/').reverse().join(''));
    },
    beforeShowDay: function (date) {
        var year = date.getFullYear();
        var month = calendario.padNumero(date.getMonth() + 1);
        var day = calendario.padNumero(date.getDate());
        var dateString = year.toString() + month.toString() + day.toString();

        var gotDate = jQuery.inArray(dateString, calendario.datas);
        if (gotDate >= 0) {
            return [true, "ui-state-highlight"];
        }
        return [true, ""];
    }
});

It works until dates are included. The problem is that the more dates I select, or the more times I include in date X, the fields of timepicker those that were already there begin not to be displayed in the Focus.

I created a fiddle for viewing this.

Click on the calendar date it will add a field for selecting hours.

  • Here the timepicker never appears, not even the first time I select a date.

2 answers

1


The code is set to remove the date if it has already been selected, you can delete this function by commenting on the line:

//this.removeDate(index);

See on Jsfiddle

  • It is made to work like this. One can delete the date selects this way. Memso without it the time selection field is not displayed.

0

Each time you remove elements from the DOM, the event receiver that was connected to that element is lost.

For example:

dataOrganiza: function(){
        var organizar = $("#horas_sel div").toArray().sort(this.sorteio);
        $("#horas_sel div").remove();

In this last line the .remove() removes the elements within that div. I understand the idea of re-organizing dates but this generates this problem because it breaks the loop between element and its receiver (Event Handler).

Solution:

I suggest delegating these event headsets. You can really get them out of this namespace and put in the code next to // inicia calendário. That is to say:

Instead of this code inside the setTimeout:

$('#plusicon_'+data).click(function(){
    calendario.addHora(data)
});

you may have (outside the calendário:

$(document).on('click', '[id^="plusicon_"]', function () {
    calendario.addHora(this.id.split('_').pop());
});

In this new code I’ll get the data to own ID using this.id.split('_').pop() that gives me the last piece breaking that string by the caractér: _

Example: http://jsfiddle.net/bwb9605y/6/

  • I did your test. Even inside your Fiddle it still doesn’t display the time selection field. Is there any other way? Your test worked?

Browser other questions tagged

You are not signed in. Login or sign up in order to post.