Nous avons besoin de présenter deux composants p:calendar à l'utilisateur, représentant chacun une date de début et de fin. Les deux dates comportent des dates, des heures et des minutes. PrimeFaces a parfaitement mindate
, maxdate
, minHour
, maxHour
, minMinute
y minMinute
attributs disponibles.
L'exigence est maintenant :
Il est impossible de donner à la date de début une valeur supérieure ou égale à la date de fin. Il est impossible de donner à la date de fin une valeur inférieure ou égale à la date de fin.
L'équation suivante devrait être vraie :
begin datetime < end datetime
Maintenant nous avons essayé le JSF suivant :
<p:calendar id="begin-date"
value="#{debugManager.selectedBeginDate}"
mindate="#{debugManager.minBeginDate}"
maxdate="#{debugManager.maxBeginDate}"
maxHour="#{debugManager.maxBeginHour}"
maxMinute="#{debugManager.maxBeginMinute}"
pattern="yyyy-MM-dd HH:mm"
showButtonPanel="true"
readonlyInput="true"
navigator="true"
showOn="button"
required="true">
<p:ajax event="dateSelect" update="end-date" />
</p:calendar>
<p:calendar id="end-date"
value="#{debugManager.selectedEndDate}"
mindate="#{debugManager.minEndDate}"
minHour="#{debugManager.minEndHour}"
minMinute="#{debugManager.minEndMinute}"
pattern="yyyy-MM-dd HH:mm"
showButtonPanel="true"
readonlyInput="true"
navigator="true"
showOn="button">
<p:ajax event="dateSelect" update="begin-date" />
</p:calendar>
Voici un exemple de méthode min/max (sans tenir compte de la date de fin) :
public Date getMinEndDate()
{
return this.getSelectedBeginDate();
}
Comme vous pouvez le voir, la date de fin minimale est la date de début actuellement sélectionnée par AJAX. Le fait de définir une date de fin empêche de définir la date de début au-delà de la date de fin.
Les problèmes commencent lorsqu'on fait intervenir le temps dans l'équation...
Comme l'interface de p:calendar a des méthodes distinctes, le bean doit fournir la logique :
public int getMinEndHour()
{
Date selectedBeginDate = this.getSelectedBeginDate();
Date selectedEndDate = this.getSelectedEndDate();
if ( selectedBeginDate != null && DateUtil.isSameDay( selectedBeginDate, selectedEndDate ) )
{
return DateUtil.getHourOf( selectedBeginDate );
}
return ComplianceConstants.DEFAULT_COMPLIANCE_CASE_MIN_END_HOUR;
}
En fait, cela ne s'applique que si une date de début a été fixée et si les dates de début et de fin sont actuellement les mêmes, restreindre l'heure de fin sélectionnable ( minHour
de la date de fin) à l'heure de début.
Opérations :
Set the begin datetime to 2013-04-20 12:34 (legit)
Set the end datetime to 2013-04-22 00:00 (legit)
Maintenant, l'heure de la date de fin est fixée à 00:00 et la sélection d'une date de calendrier 2013-04-20 devrait être autorisée tant que l'heure de fin est ajustée à au moins 12:35.
Le composant p:calendar ne peut cependant pas savoir cela et maintenant
sets the end datetime to 2013-04-20 00:00 (legit, but false)
...
Le problème est que lorsque l'utilisateur appuie sur une nouvelle date de fin dans le calendrier, les attributs mindate/maxdate ne peuvent pas empêcher l'utilisateur d'appuyer sur la même date que la date de début. Si la date de fin temps se trouve maintenant devant le même heure de début de la date on ne peut rien y faire (ce qui est faux).
Le problème suivant est que l'utilisateur peut fermer le calendrier et appuyer sur le bouton "Envoyer" pour insérer de fausses données dans la base de données. Bien sûr, un validateur pourrait/devrait être exécuté, mais nous devons trouver un moyen d'y parvenir sans validateur. .
Ce que nous essayions ensuite, c'était de corriger le setSelectedBeginDate( Date selectedBeginDate )
y setSelectedEndDate( Date selectedEndDate )
méthodes de réglage de l'ensemble java.util.Date
les portions de temps si les dates étaient le même jour. Quelque chose comme ça :
public void adjustSelectedEndDate()
{
if ( this.selectedEndDate != null )
{
this.log.infov( "adjustSelectedEndDate: b-hour = {0}, e-hour = {1}", DateUtil.getHourOf( this.selectedBeginDate ), DateUtil.getHourOf( this.selectedEndDate ) );
if ( DateUtil.isSameDay( this.selectedBeginDate, this.selectedEndDate ) &&
( DateUtil.getHourOf( this.selectedEndDate ) < DateUtil.getHourOf( this.selectedBeginDate ) ) ||
DateUtil.getHourOf( this.selectedEndDate ) == DateUtil.getHourOf( this.selectedBeginDate ) && DateUtil.getMinuteOf( this.selectedEndDate ) <= DateUtil.getMinuteOf( this.selectedBeginDate ) )
{
this.log.info( "Adjusting selected end date!" );
this.selectedEndDate = DateUtil.addOneMinuteTo( DateUtil.copyTime( this.selectedBeginDate, this.selectedEndDate ) );
}
}
}
Cela nous a obligés à ajouter @this
au update
de chaque p:calendar
de sorte que les récupérateurs respectifs ( getSelectedBeginDate()
y getSelectedEndDate
+ les limiteurs min/max) seront appelés lors de la mise à jour.
Placer un @this
sur la mise à jour confond toutefois les composants p:calendar, rendant les curseurs de temps glissants une seule fois. Les événements de glissement ultérieurs sont tout simplement ignorés, et le comportement est cassé.
Q's
- Comment abordez-vous généralement la résolution de ce problème ?
- Est-ce que l'on utilise
p:remoteCommand
le moyen d'obtenir ce que nous voulons ?
Facultatif Q :
- Pourquoi le p:calendar de PrimeFaces n'a-t-il pas été implémenté pour fournir un minDateTime et un maxDateTime uniques, ce qui pourrait potentiellement résoudre les problèmes en question ?
Je parie que le scénario que j'ai décrit a déjà été résolu auparavant. J'apprécierais beaucoup si vous pouviez décrire l'approche que vous avez adoptée pour le résoudre (ou même partager une solution partielle).