Le sélecteur de date AngularJS déclenche plusieurs fois l'événement onchange
-
20-12-2019 - |
Question
J'ai cherché un cueilleur de rendez-vous approprié pour AngularJS et je me suis installé sur l'utilisation de pickadate.js
en raison de sa belle interface utilisateur mobile ainsi que d'une directive personnalisée pour permettre l'intégration angulaire, comme indiqué dans cet article de blog
http://www.codinginsight.com/angularjs-and-pickadate/
Je voulais étendre la directive dans le billet de blog ci-dessus avec un événement pour appeler une fonction dans mon contrôleur lorsque la valeur change.Le code complet de la directive étendue est affiché ci-dessous
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);
}
};
});
Je peux maintenant utiliser cette directive avec un événement de changement comme indiqué ci-dessous dans mon HTML
<input type="text" pick-a-date="curDate" change="onChange()" />
Cela fonctionne mais l'événement OnChange est déclenché plusieurs fois pour un seul changement.Avez-vous une idée sur la façon dont je peux le faire tirer une seule fois ?J'ai créé un plunker pour démontrer le problème
http://plnkr.co/edit/3NcaAknd4GpelJxHWUyv
Cliquez sur le champ de texte et sélectionnez une date.Vous verrez que la variable du compteur est mise à jour plusieurs fois pour un seul changement de date.
La solution
Comme @miqid a suggéré de lier une fonction entre une directive et une utilisation de contrôleur '&'
('='
doit être utilisé uniquement pour lier les variables de portée entre la directive et le contrôleur.)
Il y a également une modification supplémentaire à apporter à votre code actuel.La fonction scope.change dans updateValue()
n'est pas exécuté car il a été référencé comme scope.change.Cela doit être changé en scope.change()
.
J'ai bifurqué votre plunker et l'ai modifié pour corriger les modifications ci-dessus.
Plunker de travail fixe : http://plnkr.co/edit/oEpOxE21dXre28FpKoMc?p=preview
Le compteur n'est mis à jour qu'une seule fois pour changer.Faites-moi savoir si cela aide.
Autres conseils
Vous avez lié change
à l'intérieur de ton pick-a-date
directive utilisant '='
au lieu de '&'
.
Cette dernière liaison de portée d'isolement est recommandée pour les expressions telles que les fonctions de rappel.
Conseils pertinents de la documentation AngularJS sur directive:
Meilleur entrainement: utiliser
&attr
dans l'option scope lorsque vous souhaitez que votre directive expose une API pour la liaison aux comportements.