8 Replies Latest reply on May 5, 2011 5:17 PM by joeeoj

    How to mimic a time picker

    mteichmann.mark.teichmann.info-ag.de
      In my database and entity bean I have two fields of type datetime: StartDate and EndDate where I store date and time information.

      Now I would like to implement in my web form one field to select the Date and two fields to only select the starttime and endtime. But in the database these fields should be combined to Date + starttime as StartDate and Date + endtime as EndDate.

      (Using the combined date and time picker from RichFaces is not very userfriendly therefore I want to separate date and time).

      What would be the best approach to go for?

      Do some JavaScript and Seam remoting to fill the fields in the entity bean? Or use some kind of custom validator which does the conversion? Or do you know any examples where I can see a similar thing?
        • 1. Re: How to mimic a time picker

          Hi


          I think a saw a time picker in Web Galileo OpenSource JSF Components... Yes, you can see it in this demo


          Regards,

          • 2. Re: How to mimic a time picker
            mteichmann.mark.teichmann.info-ag.de

            Thanks for sharing this.
            While this would do the job I am somehow not happy with the visual design of this picker. It seems to be unusual to pick a time this way.
            I will try to use the following approach:


            1. Use a standard rich calendar for selecting a date
            2. Build one or two rich select boxes to select time (or hours and minutes) to select start time
            3. Follow 2. to select end time
            4. Implement a SLSB that provides a service that takes my 3 values Date, starttime, endtime and populates my entity bean using a Managed Bean as mediator. (The Managed Bean will be bound to the fields on the form. The form calls the service. The service populates my entity bean)


            It seems to me that it is a bit indirect but I have no idea if there would be another way to implement it.


            The general problem I need to solve is: How to map fields on a web form to some other fields in entity bean when this is not a 1:1 relation. Are there other ways than using a managed bean for this scenario?

            • 3. Re: How to mimic a time picker
              mteichmann.mark.teichmann.info-ag.de

              I created the following solution now: In my .xhtml page I display a date picker and four separate select boxes to select hour and minute (start and end time)


                                  <s:decorate id="dateDecoration" template="layout/edit.xhtml"
                                       for="dateCalendar">
                                       <ui:define name="label">#{messages['leavemanager.label.STARTDATE']} />
                                       <rich:calendar id="dateCalendar" value="#{timePickerHelper.theDate}"
                                            buttonLabel="#{messages['leavemanager.label.DATE']}" popup="true"
                                            isDayEnabled="isDayEnabled" dayStyleClass="dayStyleClass"
                                            datePattern="#{messages['leavemanager.date.PATTERN']}"
                                            required="true" locale="#{localeSelector.locale}">
                                            <a:support event="onchanged"
                                                 reRender="dateDecoration:dateCalendar" rendered="true" />
                                            <a:support event="onsubmit" ajaxSingle="true"  bypassUpdates="true"/>
                                            <f:facet name="header">
                                                 <h:panelGrid columns="7"
                                                      style="width:100%; background-color:#BED6F8;">
                                                      <h:outputText value="{previousYearControl}"
                                                           styleClass="rich-calendar-tool" />
                                                      <h:outputText value="{previousMonthControl}"
                                                           styleClass="rich-calendar-tool" />
                                                      <h:outputText value="{currentMonthControl}"
                                                           styleClass="rich-calendar-month" />
                                                      <h:outputText value="{nextMonthControl}"
                                                           styleClass="rich-calendar-tool" />
                                                      <h:outputText value="{nextYearControl}"
                                                           styleClass="rich-calendar-tool" />
                                                      <h:outputText value="" styleClass="rich-calendar-tool-close" />
                                                      <h:outputText value="{closeControl}"
                                                           styleClass="rich-calendar-tool " />
                                                 </h:panelGrid>
                                            </f:facet>
                                       </rich:calendar>
                                  </s:decorate>
                                  <s:decorate id="startTimeDecoration" template="layout/edit.xhtml">
                                       <ui:define name="label">#{messages['leavemanager.label.STARTTIME']}</ui:define>
                                       <h:selectOneMenu id="startHours"
                                            value="#{timePickerHelper.startHour}">
                                            <s:selectItems var="hour" label="#{hour}"
                                                 value="#{timePickerHelper.getHourOptions()}"
                                                 hideNoSelectionLabel="true" />
                                            <a:support event="onsubmit" ajaxSingle="true" bypassUpdates="true"/>
                                       </h:selectOneMenu>
                                  :
                                  <h:selectOneMenu id="startMinutes"
                                            value="#{timePickerHelper.startMinute}">
                                            <s:selectItems var="minute" label="#{minute}"
                                                 value="#{timePickerHelper.getMinuteOptions()}"
                                                 hideNoSelectionLabel="true" />
                                            <a:support event="onsubmit" ajaxSingle="true"  bypassUpdates="true"/>
                                       </h:selectOneMenu>
                                  </s:decorate>
                                  <s:decorate id="endTimeDecoration" template="layout/edit.xhtml">
                                       <ui:define name="label">#{messages['leavemanager.label.ENDTIME']}</ui:define>
                                       <h:selectOneMenu id="endHours" value="#{timePickerHelper.endHour}">
                                            <s:selectItems var="hour" label="#{hour}"
                                                 value="#{timePickerHelper.getHourOptions()}"
                                                 hideNoSelectionLabel="true" />
                                            <a:support event="onsubmit" ajaxSingle="true"  bypassUpdates="true"/>
                                       </h:selectOneMenu>
                                  :
                                  <h:selectOneMenu id="endMinutes" value="#{timePickerHelper.endMinute}">
                                            <s:selectItems var="minute" label="#{minute}"
                                                 value="#{timePickerHelper.getMinuteOptions()}"
                                                 hideNoSelectionLabel="true" />
                                            <a:support event="onsubmit" ajaxSingle="true"  bypassUpdates="true"/>
                                       </h:selectOneMenu>
                                  </s:decorate>
              
              


              All these elements are bound to a Seam bean:


              @Name("timePickerHelper")
              @Scope(ScopeType.EVENT)
              public class TimePickerBean implements Serializable {
                   
              private static final String[] hourOptions = {
                   "00",
                   "01",
                   ...
                   "22",
                   "23"
              };
              
              private static final String[] minuteOptions = {
                   "00",
                   "01",
                   ...
                   "58",
                   "59"     
              };
              
              private Date theDate;
              private String startHour;
              private String startMinute;
              private String endHour;
              private String endMinute;
              
              public TimePickerBean() {
                   theDate = new Date();
                   startHour = "00";
                   startMinute = "00";
                   endHour = "00";
                   endMinute = "00";
              }
              ...
              Getters and Setters here...
              


              This is managed by a controller:


              @Scope(ScopeType.CONVERSATION)
              @Stateful
              @Name("timeEntryAction")
              public class TimeEntryActionImpl implements TimeEntryAction {
                   
                   private static final long serialVersionUID = 6068522266849679060L;
                   
                   @In("#{timePickerHelper}")
                   private TimePickerBean timePickerBean;
              ...
              @End
                   public void create(TimeEntry timeEntry) {
                        Date startDate = new Date(timePickerBean.getTheDate().getTime());
                        Date endDate = new Date(timePickerBean.getTheDate().getTime());
                        
                        if (timeEntry != null){
                             startDate.setHours(Integer.valueOf(timePickerBean.getStartHour()));
                             startDate.setMinutes(Integer.valueOf(timePickerBean.getStartMinute()));
                             endDate.setHours(Integer.valueOf(timePickerBean.getEndHour()));
                             endDate.setMinutes(Integer.valueOf(timePickerBean.getEndMinute()));
              ...
              



              Hopefully somebody can make use of this some time...
                   


              • 4. Re: How to mimic a time picker
                jigneshmpatel

                Can you post a sourcecode or email me at jigneshmpatel@gmail.com.
                I have littlebit different requirement but I will customize it.

                • 5. Re: How to mimic a time picker
                  mteichmann.mark.teichmann.info-ag.de

                  Jignesh,


                  the above code covers the complete functionality of the picker that I am using. If you need some more advice on this then try to ask some detailed questions.
                  Unfortunately I cannot post more sourcecode because it is an inhouse application.


                  The main idea of my code above is that I separate input fields on the web page from date fields in my entity and database. Although I only use one field in database for storing a datetime value I offer separate controls for date and time in the frontend. This is especially helpful if you have multiple time ranges on the same date.

                  • 6. Re: How to mimic a time picker
                    jigneshmpatel

                    Thanks for prompt response mark.


                    So more specific question:
                    TimeEntryActionImpl and TimeEntryAction have to do anything for Timer Component or they are more related to your inhouse application? 


                    Can you mention steps required to make time component working.


                    • 7. Re: How to mimic a time picker
                      mteichmann.mark.teichmann.info-ag.de

                      Sorry, my code snippet of the controller indeed was a bit too small to understand what I am doing. Class TimeEntryActionImpl is my controller that actually saves the entity TimeEntry into the database. This class is implementing interface TimeEntryAction. This is needed because it is a stateful session bean.


                      @Scope(ScopeType.CONVERSATION)
                      @Stateful
                      @Name("timeEntryAction")
                      public class TimeEntryActionImpl implements TimeEntryAction {
                      
                           private static final long serialVersionUID = 6068522266849679060L;
                      
                           @In("#{timePickerHelper}")
                           private TimePickerBean timePickerBean;
                      
                           @PersistenceContext
                           @In(create = true)
                           EntityManager entityManager;
                           
                           private Date startDate ;
                           private Date endDate;
                      
                           @End
                           public void create(TimeEntry timeEntry) {
                                this.startDate = new Date(timePickerBean.getTheDate().getTime());
                                this.endDate = new Date(timePickerBean.getTheDate().getTime());
                                if (timeEntry != null){
                                     startDate.setHours(Integer.valueOf(timePickerBean.getStartHour()));
                                     startDate.setMinutes(Integer.valueOf(timePickerBean.getStartMinute()));
                                     endDate.setHours(Integer.valueOf(timePickerBean.getEndHour()));
                                     endDate.setMinutes(Integer.valueOf(timePickerBean.getEndMinute()));
                                     
                                     timeEntry.setStartDate(startDate);
                                     timeEntry.setEndDate(endDate);
                                     
                      ...
                                     
                                     entityManager.persist(timeEntry);
                                     entityManager.flush();
                      ...
                      
                      @Entity
                      @Table(name = "TimeEntry", schema = "dbo")
                      public class TimeEntry implements java.io.Serializable {
                      
                           private static final long serialVersionUID = -8517918098378295179L;
                           private int id;
                           private Date startDate;
                           private Date endDate;
                           
                           public TimeEntry() {
                           }
                      
                           public TimeEntry(int id, Date startDate, Date endDate) {
                                this.id = id;
                                this.startDate = startDate;
                                this.endDate = endDate;
                           }
                      
                           @Id
                           @GeneratedValue
                           @Column(name = "id", unique = true, nullable = false)
                           @NotNull
                           public int getId() {
                                return this.id;
                           }
                      
                           public void setId(int id) {
                                this.id = id;
                           }
                      
                           @Temporal(TemporalType.TIMESTAMP)
                           @Column(name = "StartDate", length = 23)
                           public Date getStartDate() {
                                return this.startDate;
                           }
                      
                           public void setStartDate(Date startDate) {
                                this.startDate = startDate;
                           }
                      
                           @Temporal(TemporalType.TIMESTAMP)
                           @Column(name = "EndDate", length = 23)
                           public Date getEndDate() {
                                return this.endDate;
                           }
                      
                           public void setEndDate(Date endDate) {
                                this.endDate = endDate;
                           }
                      
                      
                      @Local
                      public interface TimeEntryAction {
                      
                      
                           public abstract void create(TimeEntry timeEntry);
                           
                           public void destroy();
                           }
                      
                      


                      • 8. Re: How to mimic a time picker
                        joeeoj

                        I was reading this article but ended up writing my own code, thought I would share it here:


                        On the model:


                        @Transient
                             public Date getDate() {
                                  return datetime;
                             }
                             
                             public void setDate(Date date) {
                                  if (datetime != null) {
                                       Calendar oldcal = new GregorianCalendar();
                                       oldcal.setTime(datetime);
                                       Calendar newcal = new GregorianCalendar();
                                       newcal.setTime(date);
                                       newcal.set(Calendar.AM_PM, oldcal.get(Calendar.AM_PM));
                                       newcal.set(Calendar.HOUR, oldcal.get(Calendar.HOUR));
                                       newcal.set(Calendar.MINUTE, oldcal.get(Calendar.MINUTE));
                                       setDatetime(newcal.getTime());
                                  }
                                  else setDatetime(date);
                             }
                             
                             @Transient
                             public String getTime() {
                                  return TimeBean.formatTime(datetime);
                             }
                             
                             public void setTime(String timeString) {
                                  if (datetime == null) return;
                                  Date time = TimeBean.parseTime(timeString);
                                  if (time == null) return;
                                  Calendar timecal = new GregorianCalendar();
                                  timecal.setTime(time);
                                  Calendar cal = new GregorianCalendar();
                                  cal.setTime(datetime);
                                  cal.set(Calendar.AM_PM, timecal.get(Calendar.AM_PM));
                                  cal.set(Calendar.HOUR, timecal.get(Calendar.HOUR));
                                  cal.set(Calendar.MINUTE, timecal.get(Calendar.MINUTE));
                                  setDatetime(cal.getTime());
                             }


                        on a bean somewhere:


                             public List<String> getTimeOptions() {
                                  List<String> timeOptions = new ArrayList<String>();
                                  Calendar cal = Calendar.getInstance();
                                  cal.set(Calendar.AM_PM, Calendar.AM);
                                  cal.set(Calendar.HOUR, 0);
                                  cal.set(Calendar.MINUTE, 0);
                                  int startDate = cal.get(Calendar.DATE);
                                  while (cal.get(Calendar.DATE) == startDate) {
                                       timeOptions.add(TimeBean.formatTime(cal.getTime()));
                                       cal.add(Calendar.MINUTE, 15);
                                  }
                                  return timeOptions;
                                  
                             }