El selector de fechas de AngularJS activa el evento de cambio varias veces
-
20-12-2019 - |
Pregunta
He estado buscando un selector de fecha adecuado para AngularJS y me decidí por usar Pickadate.js
debido a su hermosa interfaz de usuario móvil junto con una directiva personalizada para permitir la integración angular como se muestra en esta publicación de blog
http://www.codinginsight.com/angularjs-and-pickadate/
Quería ampliar la directiva en la publicación de blog anterior con un evento para llamar a una función en mi controlador cuando cambia el valor.El código completo de la directiva extendida se muestra a continuación.
angular.module('plunker').directive('pickADate', function () {
return {
restrict: "A",
scope: {
pickADate: '=',
minDate: '=',
maxDate: '=',
change: '='
},
link: function (scope, element, attrs) {
element.pickadate({
onSet: function (e) {
if (scope.$$phase || scope.$root.$$phase) // we are coming from $watch or link setup
return;
var select = element.pickadate('picker').get('select'); // selected date
scope.$apply(function () {
if (e.hasOwnProperty('clear')) {
scope.pickADate = null;
return;
}
if (!scope.pickADate)
scope.pickADate = new Date(0);
scope.pickADate.setYear(select.obj.getFullYear());
// Interesting: getYear returns only since 1900. Use getFullYear instead.
// It took me half a day to figure that our. Ironically setYear()
// (not setFullYear, duh) accepts the actual year A.D.
// So as I got the $#%^ 114 and set it, guess what, I was transported to ancient Rome 114 A.D.
// That's it I'm done being a programmer, I'd rather go serve Emperor Trajan as a sex slave.
scope.pickADate.setMonth(select.obj.getMonth());
scope.pickADate.setDate(select.obj.getDate());
});
},
onClose: function () {
element.blur();
}
});
function updateValue(newValue) {
if (newValue) {
scope.pickADate = (newValue instanceof Date) ? newValue : new Date(newValue);
// needs to be in milliseconds
element.pickadate('picker').set('select', scope.pickADate.getTime());
} else {
element.pickadate('picker').clear();
scope.pickADate = null;
}
}
updateValue(scope.pickADate);
element.pickadate('picker').set('min', scope.minDate ? scope.minDate : false);
element.pickadate('picker').set('max', scope.maxDate ? scope.maxDate : false);
scope.$watch('pickADate', function (newValue, oldValue) {
if (newValue == oldValue)
return;
updateValue(newValue);
// call change function
scope.change;
}, true);
scope.$watch('minDate', function (newValue, oldValue) {
element.pickadate('picker').set('min', newValue ? newValue : false);
}, true);
scope.$watch('maxDate', function (newValue, oldValue) {
element.pickadate('picker').set('max', newValue ? newValue : false);
}, true);
}
};
});
Ahora puedo usar esta directiva con el evento de cambio como se muestra a continuación en mi HTML
<input type="text" pick-a-date="curDate" change="onChange()" />
Funciona, pero el evento OnChange se activa varias veces para un solo cambio.¿Alguna idea de cómo puedo hacer que se dispare solo una vez?He creado un plunker para demostrar el problema.
http://plnkr.co/edit/3NcaAknd4GpelJxHWUyv
Haga clic en el campo de texto y seleccione una fecha.Verá que la variable del contador se actualiza varias veces para un solo cambio de fecha.
Solución
Como @miqid sugirió vincular una función entre una directiva y un uso de controlador '&'
('='
debe usarse solo para vincular variables de alcance entre la directiva y el controlador).
También hay un cambio más que se debe realizar en su código actual.La función alcance.cambio en updateValue()
no se ejecuta porque se hace referencia a él como alcance.cambio.Esto tiene que cambiarse a scope.change()
.
Bifurqué su plunker y lo modifiqué para corregir los cambios anteriores.
Plunker de trabajo fijo: http://plnkr.co/edit/oEpOxE21dXre28FpKoMc?p=preview
El contador se actualiza solo una vez para variar.Déjeme saber si esto ayuda.
Otros consejos
Usted ha encado a change
dentro de su directiva pick-a-date
usando '='
en lugar de '&'
.
Se recomienda el Último Ajuste de Aislamiento de Aislado para expresiones como funciones de devolución de llamada.
Asesoramiento relevante de la documentación de AngularJS en Directivas :
Mejor práctica: Use GeneracDicetAnDode en la opción de alcance cuando desea que su directiva exponga una API para la obligación a los comportamientos.