Clarity: Time Picker component (new)

Created on 27 Mar 2020  路  6Comments  路  Source: vmware/clarity

Summary

See #474.

Use case

Time is present almost everywhere in the online world, scheduling appointments, looking for public transport, reminders, deadlines, entity timestamps, etc.
This component should make it easy for users to quickly select a time on any device (PC, mobile, SR).

Examples

Same as the date-picker, this is a wrapped form control. (container gets added if not provided by the user).

<input type="time" clrTime>

<clr-time-container>
  <input type="time" clrTime>
</clr-time-container>

Typical situation showcase - scheduling an appointment during the working hours (only start time shown). Initial value might be used for editing an existing appointment for example.

<form clrForm>
  <clr-time-container [clrView]="TimepickerViewEnum.DIGITAL">
    <label>Start time</label>
    <input type="time" name="start_time" [clrTime]="initialValue"
           clrMinuteStep="5" min="8:30" max="17:00">
  </clr-time-container>
</form>

API

  • ClrTimeContainer

    • Input clrPosition - where should the time-picker popover open

    • Input clrView (name pending) - digital, analog (can be done in another iteration)

    • Input clrType (name pending) - AM/PM or 24-hour (overrides locale)

    • Input clrHourStep, clrMinuteStep (if it is decided to not use step on the input)

  • ClrTimeInput

    • Input clrTime - used to set value

    • Input min - minimum time (HH:mm)

    • Input max - maximum time (HH:mm)

    • Input placeholder - input placeholder

    • Input step (if it is decided to not use hour & minute step on the container)

    • Output clrTimeChanged - emits a time value every time it changes

  • ClrTimepickerDigital
  • ClrTimepickerViewManager

Implementation plan

It might be worth to at least partly merge time-picker and date-picker since they are similar components. In the future they will also be used together in a date-time-picker.

  • What parts of the code are affected?

This is a new module (but documentation and dev demo pages are of course affected).

  • Will you introduce new services, components or directives?

    • LocaleHelperService - load locale time format (CLDR)
    • TimeIOService - takes care of displaying formatted values in the input field
      and also parsing and validating user-typed input (keyboard input)
    • TimeNavigationService (name pending) - handles actions from the time-picker popover
      (time-picker input)
    • ViewManagerService - handles displaying of different time-pickers and their variations
      (AM/PM vs 24-hour format for example)
    • TimepickerEnabledService - determines whether native or Clarity time input should be used
      (user agent, resolution, browser which don't support input type='time')
    • TimepickerFocusService - might be needed to handle focus in the time-picker popover
    • TimeFormControlService - very similar to date-picker
  • Can you describe the basic flow of information between classes?

Very similar to the date-picker. Time input uses the TimeIOService to parse, validate and format user input. When the time-picker popover is open, it uses the TimeNavigationService to change the currently selected time, that gets in turn sent to the input componentand finally the value of the input field is changed too.

  • Does this introduce asynchronous behaviors?

No (if I understood it correctly)

  • Will you need to refactor existing Clarity code?

Only if it is decided to partly merge date & time pickers.

  • Will reasonable performance require optimizations?

No

  • Will it need to access native elements (and be incompatible with server-side rendering)?

The input component needs to access the native element of its input field to change its value.

Questions and thoughts

  • should a 'reset' button be included?
  • by default a time picker allows hours and minutes to be selected, should we provide the option to select seconds and/or milliseconds?
  • in my opinion the easiest way to provide a 'time' value to the users would be using a Date instance rather than a custom Time or angular provided Time (which doesn't have seconds).

Conclusion

I am expecting to finish the first draft within ~10 days of finalizing the design/proposal discussions. Other than a few pointers during the design process, I should not need much help with the actual development. I however have a few gaps in a11y knowledge.

@clangular enhancement request in progress design new component

Most helpful comment

Hey @martinbrom - thanks for starting this component and taking this on. Here is some quick feedback on the initial directive/component design that you have put together. Most of this is re-stating what you proposed but I'm trying to break it down a bit by component or directive and add my preferences / opinions. I also fleshed out the demo templates in order to think through the inputs/outpus and services.

ClrTimepicker v1 @ Inputs:

  1. placeholder - mimic native browser attribute
  2. clrTime - (HH:MM || HH:MM:SS ) my preference is for implementing HH:MM in this contribution
    2.1 Leave room to add SS (or milliseconds as enhancements later)
    2.2 should only take a date object (I need to confirm with the team on this, we initially took both a string and a Date obj for datepicker and it caused a lot of issues. I _think_ we only want to take dates for this input but i'm not 馃挴 on that.
  3. min/max - mimic native browser attributes
  4. disabled - mimic native browser attributes

ClrTimepicker v1 @ Outputs

  1. clrTimeChange

ClrTimeContainer v1 @ Input

  1. clrPosition - the new way to handle popovers is to use the ClrPopoverModuleNext utils
  2. clrPosition default should be the same as the ClrDatepicker default

Services

I didn't go deep into services yet but it might make sense to share a similar approach that is impleented in the datepicker. e.g

DateIOService (TimeIOService)

yes, this seems good

  1. Might consider a Hour model, second model but not sure if thats overkill right now
  2. init localized time (12 vs 24 hour display)
  3. toLocalDisplayFormatString
  4. validation for user supplied input
  5. utils that get date from a string and a string from a date

LocaleHelperService

If possible we should reuse or extend whats in the datepicker version of this service. May need to extract it / reorganize the files / folders but POC could import it from the datepicker location.

TimeNavigationService

tbd - enhancements

ViewManagerService

tbd - enhancements

TimepickerEnabledService

If possible we should reuse or extend whats in the datepicker version of this service. May need to extract it / reorganize the files / folders but POC could import it from the datepicker location. This may mean a small refacotring / renaming of the exiting service

TimepickerFocusService

yes, if possible re-use datepicker serivce but may need to rename/refactor a bit.

TimeFormControlService

Yes

Demos / Example usages

Basic Usage (recomendation should be to use inside the container)

<form clrForm>
    <clr-time-container>
        <label>Basic Time Demo</label>
        <input type="time" clrTime name="demo" [(ngModel)]="demo">
    </clr-time-container>
</form>

Template drive form

  <form clrForm #timeForm="ngForm">
    <h4>Template Driven Timepicker</h4>
    <clr-time-container>
        <label>Enter Time</label>
        <input type="time" name="date" [(ngModel)]="date" clrTime>
    </clr-time-container>
</form>

Reactive form

<form clrForm [formGroup]="timeForm">
    <h4>Reactive Form Demo</h4>
    <clr-time-container>
        <label>Date</label>
        <input type="time" clrTime formControlName="time"/>
    </clr-time-container>
</form>

min/max

<form clrForm>
    <clr-time-container>
        <label>Min/Max times: </label>
        <input type="time" clrTime name="demo" [(ngModel)]="demo" min="09:00" max="18:00">
    </clr-time-container>
</form>

Consumer supplied position

<form clrForm>
    <clr-time-container clrPosition="smartPosition">
        <label>Position Demo</label>
        <input type="time" clrTime name="demo" [(ngModel)]="demo">
    </clr-date-container>
</form>
public smartPosition: ClrPopoverPositionsInterface = {
    axis: ClrAxis = ClrAxis.VERTICAL;
    side: ClrSide = ClrSide.AFTER;
    anchor: ClrAlignment.END;
    content: ClrAlignment.START;
}



md5-44e43f69e2c05553aef1a027c66787aa



```typescript
public customDateTimeObject = new Date();

Future enhancements:

  1. ClrTimepickerViewManager @ Inputs
    1.1 Input clrView (name pending) - digital, analog (can be done in another iteration)
    1.2 I would change clrView to clrTimeMode = ClrTimeView.DIGITAL || ClrTimeView.ANALOG
  2. ClrTimepickerViewManager - handles swapping between digital and analog views
    3.1 - ClrDigitalTime (view / component)
    3.2 - ClrAnalogTime (view / component)
  3. Analog View
  4. Quickpicker

    Notes

  5. Lets use / extend as much as possible from the datepicker for the initial MVP/POC They do need to me merged at some point but I don't want that to get in the way of starting this. Structure is likely to be somethig like

    • DateTimePicker

      • datepicker ... Stuff that is specific to datepicker (already exists)

      • timepicker ... Stuff that is specific to timepicker

      • common ... serivices and utils that both date & time pickers need

  6. imo no reset button for now, could be an enhancement but I'm concerenedthere isn't a design for it (I may be wrong on this, need to confirm the behavior in datepicker)
  7. lets keep seconds and milliseconds as an enhancement
  8. Yes, I mentioned above, lets use ainstance of Date object

I'm going to try to get one or two other team members to take a look and see if Imissed anything. Feel free to continue the discussion if you have questions or comments on my feedback. Thanks again!

All 6 comments

Hey @martinbrom - thanks for starting this component and taking this on. Here is some quick feedback on the initial directive/component design that you have put together. Most of this is re-stating what you proposed but I'm trying to break it down a bit by component or directive and add my preferences / opinions. I also fleshed out the demo templates in order to think through the inputs/outpus and services.

ClrTimepicker v1 @ Inputs:

  1. placeholder - mimic native browser attribute
  2. clrTime - (HH:MM || HH:MM:SS ) my preference is for implementing HH:MM in this contribution
    2.1 Leave room to add SS (or milliseconds as enhancements later)
    2.2 should only take a date object (I need to confirm with the team on this, we initially took both a string and a Date obj for datepicker and it caused a lot of issues. I _think_ we only want to take dates for this input but i'm not 馃挴 on that.
  3. min/max - mimic native browser attributes
  4. disabled - mimic native browser attributes

ClrTimepicker v1 @ Outputs

  1. clrTimeChange

ClrTimeContainer v1 @ Input

  1. clrPosition - the new way to handle popovers is to use the ClrPopoverModuleNext utils
  2. clrPosition default should be the same as the ClrDatepicker default

Services

I didn't go deep into services yet but it might make sense to share a similar approach that is impleented in the datepicker. e.g

DateIOService (TimeIOService)

yes, this seems good

  1. Might consider a Hour model, second model but not sure if thats overkill right now
  2. init localized time (12 vs 24 hour display)
  3. toLocalDisplayFormatString
  4. validation for user supplied input
  5. utils that get date from a string and a string from a date

LocaleHelperService

If possible we should reuse or extend whats in the datepicker version of this service. May need to extract it / reorganize the files / folders but POC could import it from the datepicker location.

TimeNavigationService

tbd - enhancements

ViewManagerService

tbd - enhancements

TimepickerEnabledService

If possible we should reuse or extend whats in the datepicker version of this service. May need to extract it / reorganize the files / folders but POC could import it from the datepicker location. This may mean a small refacotring / renaming of the exiting service

TimepickerFocusService

yes, if possible re-use datepicker serivce but may need to rename/refactor a bit.

TimeFormControlService

Yes

Demos / Example usages

Basic Usage (recomendation should be to use inside the container)

<form clrForm>
    <clr-time-container>
        <label>Basic Time Demo</label>
        <input type="time" clrTime name="demo" [(ngModel)]="demo">
    </clr-time-container>
</form>

Template drive form

  <form clrForm #timeForm="ngForm">
    <h4>Template Driven Timepicker</h4>
    <clr-time-container>
        <label>Enter Time</label>
        <input type="time" name="date" [(ngModel)]="date" clrTime>
    </clr-time-container>
</form>

Reactive form

<form clrForm [formGroup]="timeForm">
    <h4>Reactive Form Demo</h4>
    <clr-time-container>
        <label>Date</label>
        <input type="time" clrTime formControlName="time"/>
    </clr-time-container>
</form>

min/max

<form clrForm>
    <clr-time-container>
        <label>Min/Max times: </label>
        <input type="time" clrTime name="demo" [(ngModel)]="demo" min="09:00" max="18:00">
    </clr-time-container>
</form>

Consumer supplied position

<form clrForm>
    <clr-time-container clrPosition="smartPosition">
        <label>Position Demo</label>
        <input type="time" clrTime name="demo" [(ngModel)]="demo">
    </clr-date-container>
</form>
public smartPosition: ClrPopoverPositionsInterface = {
    axis: ClrAxis = ClrAxis.VERTICAL;
    side: ClrSide = ClrSide.AFTER;
    anchor: ClrAlignment.END;
    content: ClrAlignment.START;
}



md5-44e43f69e2c05553aef1a027c66787aa



```typescript
public customDateTimeObject = new Date();

Future enhancements:

  1. ClrTimepickerViewManager @ Inputs
    1.1 Input clrView (name pending) - digital, analog (can be done in another iteration)
    1.2 I would change clrView to clrTimeMode = ClrTimeView.DIGITAL || ClrTimeView.ANALOG
  2. ClrTimepickerViewManager - handles swapping between digital and analog views
    3.1 - ClrDigitalTime (view / component)
    3.2 - ClrAnalogTime (view / component)
  3. Analog View
  4. Quickpicker

    Notes

  5. Lets use / extend as much as possible from the datepicker for the initial MVP/POC They do need to me merged at some point but I don't want that to get in the way of starting this. Structure is likely to be somethig like

    • DateTimePicker

      • datepicker ... Stuff that is specific to datepicker (already exists)

      • timepicker ... Stuff that is specific to timepicker

      • common ... serivices and utils that both date & time pickers need

  6. imo no reset button for now, could be an enhancement but I'm concerenedthere isn't a design for it (I may be wrong on this, need to confirm the behavior in datepicker)
  7. lets keep seconds and milliseconds as an enhancement
  8. Yes, I mentioned above, lets use ainstance of Date object

I'm going to try to get one or two other team members to take a look and see if Imissed anything. Feel free to continue the discussion if you have questions or comments on my feedback. Thanks again!

I have a few comments/amendments to the above.

1) I don't want to support Date objects. The biggest reason is timezones, but also that the input[type="time"] format is always in 24h hh:mm or hh:mm:ss format. https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/time. This means the 'consumer supplied date object' API is not to be supported. It also means you're always dealing with a standard format.
2) I think seconds have to be considered, because HTML spec supports it when using step. Again, follow the HTML input spec tightly.
3) The input should conform to standard HTML attributes like step and min.
4) We don't need a timeChange output, Angular already provides change event handlers for inputs.
5) There should be fewer services (like the view manager service) as compared with the date picker. The date picker has many views to manage, but time is much simpler. Don't force services that don't have a purpose.

Why not use native HTML attribute value as initialValue?

<input type="time" clrTime value="08:15">

@belyan Angular forms track their values using Template Driven or Reactive form approaches. If you aren't using Angular controls, then you can't use clrTime so it's unnecessary to include. The values should always be set in the controller model.

Is this still being worked on?

The feature request here has been captured into our list and we鈥檙e going to take it into consideration as we develop Clarity Core capabilities. In an effort to clean up our backlog and focus our attention, I鈥檓 going to close this as captured in our feature requests. Please follow our development and releases to see when we release relevant components to make this possible. Future feature requests can be made in our GitHub Discussions.

Was this page helpful?
0 / 5 - 0 ratings