jueves, 2 de febrero de 2017

Angular UI Bootstrap. Datepicker de un rango de fechas.

Para definir en nuestros formularios de angular unos datepicker muy útiles.

Primero definimos los campos en la página html.

Vamos a crear dos datepicker que definan un rango, no permitiendo que el rango final sea superior al inicial. Además el inicial solo podrá elegirse el primer día de un mes y para el final solo el último día de un mes.

Creamos una fecha para un rango inicial:

<div class="col-input">
    <div class="form-group">
        <label for="fechaInicio">Fecha de Inicio</label>
        <div class="input-group">
            <input id="fechaInicio" name="fechaInicio"
                   type="text" class="form-control"
                   uib-datepicker-popup="{{$ctrl.viewModel.format}}"
                   ng-model="$ctrl.viewModel.Dto.fechaInicio"
                   ng-model-options="{timezone: 'utc'}"
                   ng-change="$ctrl.viewModel.changeFechaInicio()"
                   is-open="$ctrl.viewModel.popup1.opened"
                   datepicker-options="$ctrl.viewModel.dateOptionsFechaInicio"
                   ng-required="true"
                   close-text="Cerrar"
                   current-text="Hoy"
                   clear-text="Limpiar"
                   alt-input-formats="$ctrl.viewModel.altInputFormats"
                   ng-disabled="$ctrl.viewModel.flags.disabledFechaInicio" />
            <span class="input-group-btn">
                <button type="button" class="btn btn-default pull-left"
                        ng-click="$ctrl.viewModel.open1($event)">
                    <i class="glyphicon glyphicon-calendar"></i>
                </button>
            </span>
        </div>
    </div>
</div>

Y otra fecha para el final del rango:

<div class="col-input">
    <div class="form-group">
        <label for="fechaFin">Fecha de Fin</label>
        <div class="input-group">
            <input id="fechaFin" name="fechaFin"
                   type="text" class="form-control"
                   uib-datepicker-popup="{{$ctrl.viewModel.format}}"
                   ng-model="$ctrl.viewModel.Dto.fechaFin"
                   ng-model-options="{timezone: 'utc'}"
                   ng-change="$ctrl.viewModel.changeFechaFin()"
                   is-open="$ctrl.viewModel.popup2.opened"
                   datepicker-options="$ctrl.viewModel.dateOptionsFechaFin"
                   ng-required="true"
                   close-text="Cerrar"
                   current-text="Hoy"
                   clear-text="Limpiar"
                   alt-input-formats="$ctrl.viewModel.altInputFormats"
                   ng-disabled="$ctrl.viewModel.flags.disabledFechaFin" />
            <span class="input-group-btn">
                <button type="button" class="btn btn-default"
                        ng-click="$ctrl.viewModel.open2($event)">
                    <i class="glyphicon glyphicon-calendar"></i>
                </button>
            </span>
        </div>
    </div>
</div>

Ahora vamos a definir en nuestro ViewModel de Angular las opciones de cada campo:


this.generalDateOptions = {
    formatYear: 'yy',
    startingDay: 1,
    showWeeks: false,
    prevText: ',
    nextText: 'Sig>',
    currentText: 'Hoy'
};
 
this.dateOptionsFechaInicio          = JSON.parse(JSON.stringify(this.generalDateOptions));
this.dateOptionsFechaInicio.minMode = 'month';
this.dateOptionsFechaInicio.minDate = new Date();
 
this.dateOptionsFechaFin             = JSON.parse(JSON.stringify(this.generalDateOptions));

La variable generalDateOptions, es la configuración común a todos los campos fecha que tengamos en nuestros formularios.

Luego personalizamos algunos de los parámetros de la configuración, como por ejemplo indicamos que para la fecha de inicio, queremos selección por meses no por días (minMode='month') y que queremos que la fecha mínima seleccionamble sea la fecha actual.

A continuación vamos a preparar las funciones de callback (open1 y open2), que serán llamadas cuando se pulse en el icono para abrir el control Datepicker. Aqui vamos a hacer depender la fecha final del rango de la fecha inicial que se haya elegido, no permitiendo elegir un dia menor.
Además vamos a desactivar todos los días del mes, menos el último (disableNotLastDayOfMonth)

this.popup1 = {
    opened: false
};
this.popup2 = {
    opened: false
};

this.open1 = function ($event) {
 
      this.popup1.opened = true;
};
this.open2 = function ($event) {
      this.dateOptionsFechaFin.minDate  = this.Dto.fechaInicio;
      this.dateOptionsFechaFin.initDate = this.dateOptionsFechaFin.minDate;
      // Desactivamos todos los días del mes menos el último
      this.dateOptionsFechaFin.dateDisabled = this.disableNotLastDayOfMonth;
      this.dateOptionsFechaFin.minMode = 'month';
      this.popup2.opened = true;
};

// Función que habilita solo las fechas que son fin de mes
this.disableNotLastDayOfMonth = function (obj) {
    var date = obj.date, mode = obj.mode;
    if (date.getDate() > 27) {
        var comprobar = new Date();
        comprobar.setFullYear(date.getFullYear(), date.getMonth() + 1, 0);
 
        if (comprobar.getDay() === date.getDay()) {
            return false;
        }
    }
    return mode === 'day' && true;
};



Podeis encontrar toda las opciones y documentación en:
https://angular-ui.github.io/bootstrap/