Date time component

its bad, This should be a standard feature of the vaadin 10. :frowning: atleast should have been used DateTimeField of vaadin 8.

I am using vaadin Java components, please give me example how to use vaadin-time-picker ?

The time picker component is not yet ready. The first alpha version was released this week, and the Flow integration has not been started yet. If you want, you can create a webjar for https://github.com/vaadin/vaadin-time-picker/releases/tag/v1.0.0-alpha1 yourself and then use the low-level element API in Flow to use it.

Thank you for reply, i am using fooloomanzoodatetime-picker for now. https://vaadin.com/directory/component/fooloomanzoodatetime-picker

if anyone interested,here is my working code.

example-template.html

<!-- Dependency resources -->
<base href="https://raw-dot-custom-elements.appspot.com/fooloomanzoo/datetime-picker/2.9.1/datetime-picker/">

<link rel="import" href="datetime-picker.html">
<link rel="import" href="overlay-date-picker.html">
<link rel="import" href="overlay-datetime-picker.html">
<link rel="import" href="overlay-time-picker.html">
<link rel="import" href="../bower_components/polymer/polymer-element.html">

<!-- Defines the example-template element -->
<dom-module id="example-template">
    <template>
        <style >

    datetime-picker,
    overlay-time-picker,
    overlay-datetime-picker,
    overlay-date-picker {
      vertical-align: middle;
      font-size: 14px;
      --input-background: #d5d5d5;
      --input-color: #222;
      --input-picker-background: #d5d5d5;
      --input-picker-color: #222;
      --input-focus-background: white;
      --input-focus-color: #222;
      --inner-input-focus-background: white;
      --inner-input-focus-border-color: transparent;
      --inner-input-focus-color: #222;
    }

    .last-listen overlay-datetime-picker {
      --input-background: #82d5f4;
      --input-color: #222;
      --input-picker-background: #82d5f4;
      --input-picker-color: #222;
      --input-focus-background: #4285f4;
      --input-focus-color: #f1f1f1;
    }

        </style>
        <overlay-datetime-picker value="{{value}}"></overlay-datetime-picker>
        <p>value: [[value]
]</p>
    </template>

    <!-- Polymer boilerplate to register the example-template element -->
    <script>
        class ExampleTemplate extends Polymer.Element {
            static get is() {
                return 'example-template'
            }
        }
        customElements.define(ExampleTemplate.is, ExampleTemplate);

    </script>
</dom-module>

ExampleTemplate.java

/**
 * Simple template example.
 */
@Tag("example-template")
@HtmlImport("src/example-template.html")
@SpringComponent
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class ExampleTemplate extends PolymerTemplate<ExampleTemplate.ExampleModel> {


    /**
     * Template model which defines the single "value" property.
     */
    public interface ExampleModel extends TemplateModel {

        void setValue(Double value);
        Double getValue();
    }

    public ExampleTemplate() {
        // Set the initial value to the "value" property.
        getModel().setValue(Double.valueOf(LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()));
        getElement().addPropertyChangeListener("value", event -> {
            System.out
                    .println("DateTime is set to: " +
                            LocalDateTime.ofInstant(Instant.ofEpochMilli(getModel().getValue().longValue()),
                                    TimeZone.getDefault().toZoneId()));

        });
    }

    public void setValue(String value) {
        getModel().setValue(Double.valueOf(value));
    }

    public Double getValue() {
        return  getModel().getValue();
    }
   
}

Any progress with this? Something like this from Alain HIRSCH: https://vaadin.com/attachment/cbeb9f91-5cab-43fc-bcd0-f9ba14a6657f/datetimeVaadin.png

Alain HIRSCH:
This should be a standard feature of the vaadin component.
I hope it will be done in the future.

But if you want a quickly solution, i was working on this to train me on vaadin 10 and polymer.

i made a subclass to add the time feature to the vaadin date picker.

here is my code.
should work. But you will need to adapt for your use.
I used in french format (dd/mm/yyyy HH:mm)

client side :

<dom-module id="custom-date-picker"> 
	<template>
	</template> 
	<script>
      	class CustomDatePicker extends Vaadin.DatePickerElement  {
	        static get is() { return 'custom-date-picker'}
			
			static get template() {
				return Vaadin.DatePickerElement.template;
			}
			
	        static get observers() {
	        	return [
	              'textUpdateEvent(_userInputValue)'
	            ];
	     	}
	        	        
	        static get properties() {
	            return {
	              /**
	               * Set to false to disable this element.
	               */
	               showTime: {
	                type: Boolean,
	                value: true,
	                reflectToAttribute: true
	              },
	              hour: {
		                type: String,
		                value: '00',
		                reflectToAttribute: true
		              },
	              minute: {
		                type: String,
		                value: '00',
		                reflectToAttribute: true
		              },
		          _saveSelectedDate: {
		                type: Date
		              },
		          _selectHour: {
		                type: Object
		              },
		          _selectMinute: {
		                type: Object
		              },
	              _lastTime: {
		                type: String
		              }	,
	              _oldValue: {
		                type: String
		              },
	              _changeTxtManual: {
	                type: Boolean,
	                value: false
	              }
	            }
	        }
	        
	        _clear() {
	        	this._saveSelectedDate = null;
	        	super._clear();
	        }
	        
	        ready(){
	        	super.ready();
	        	
	        	//French
	        	super.set('i18n.firstDayOfWeek', 1);
	        	super.set('i18n.monthNames', ['Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Aout', 'Septembre', 'Octobre', 'Novembre', 'Décembre']

);

      	super.set('i18n.week', 'semaine');
      	super.set('i18n.weekdays', ['Dimanche', 'Lundi', 'Mardi', 'Mercredi', 'Jeudi', 'Vendredi', 'Samedi']

);

      	super.set('i18n.weekdaysShort', ['di','lu','ma','me','je','ve','sa']

);

      	super.set('i18n.calendar', 'calendrier');
      	super.set('i18n.clear', 'Effacer');
      	super.set('i18n.today', 'Aujourd\'hui');
      	super.set('i18n.cancel', 'Annuler');
      }
      
      
      _setTimeFeature(){
      	//Add time feature
      	var tmp = document.createElement('div');	
      	//TODO Put style in template
          tmp.innerHTML = '<div style="width: 120px;margin: auto;" class="cdp_TimeChooser"><select id="cdp_hour"></select>:<select id="cdp_minute"></select></div>';
          Polymer.dom(this.root).querySelector("vaadin-date-picker-overlay").root.querySelector("vaadin-date-picker-overlay-content").root.appendChild(tmp);
          
          this._selectHour = Polymer.dom(this.root).querySelector("vaadin-date-picker-overlay").root.querySelector("vaadin-date-picker-overlay-content").root.querySelector('#cdp_hour');
          this._selectMinute = Polymer.dom(this.root).querySelector("vaadin-date-picker-overlay").root.querySelector("vaadin-date-picker-overlay-content").root.querySelector('#cdp_minute');
          

          for(let i = 0; i < 24; i++){
          	var tmp_option = document.createElement('option');
          	tmp_option.innerHTML = '<option value="' + i + '">' + (i < 10 ? '0' + i :  i) + '</option>';
          	this._selectHour.append(tmp_option);
          }
          
          for(let i = 0; i < 60; i++){
          	var tmp_option = document.createElement('option');
          	tmp_option.innerHTML = '<option value="' + i + '">' + (i < 10 ? '0' + i :  i) + '</option>';
          	this._selectMinute.append(tmp_option);
          }
          
          
          //Events change
          this._selectHour.addEventListener('change', this._onHourChange.bind(this));
          this._selectMinute.addEventListener('change', this._onMinuteChange.bind(this));
      }
      	        
      _onHourChange(event){	
      	if(! this._changeTxtManual){
          	this.hour = event.target.value;	        	

          	if(this.showTime && super._userInputValue.length == 16){
          		super._userInputValue = super._userInputValue.substr(0, 11) + this.hour + ':' + super._userInputValue.substr(14,2);
          	}	     
      	}
      }
      
      _onMinuteChange(event){
      	if(! this._changeTxtManual){
          	this.minute = event.target.value;
          	
          	if(this.showTime && super._userInputValue.length == 16){
          		super._userInputValue = super._userInputValue.substr(0, 14) + this.minute;
          	}	
      	}
      }
      
      validate(value) {
      	value = value !== undefined ? value : this._inputValue;
      	
    	 	if(value.length > 10){
          	value = value.substr(0, 10);
          }
      	
      	if(this._saveSelectedDate){
      		super._selectedDate = this._saveSelectedDate;
      	}
      	else{
      		//Need to parse date here.
      		
      	}

          return super.validate(value);
      }
      
     textUpdateEvent(_userInputValue){		        	       		        	
      	//Time
      	if(this.showTime && _userInputValue.length == 10){
      		this._saveSelectedDate = super._selectedDate;
      		super._userInputValue = _userInputValue + ' ' + this.hour + ':' + this.minute;		
      	}
      	
      	if(this.showTime && super._userInputValue.length == 16 && (! this._lastTime  || this._lastTime !== super._userInputValue)){
      		this._lastTime = super._userInputValue;
      		this.$server.clientSetDateTime(super._userInputValue);
      		this.updateSelectTime();	        		
      	}		        	
      }
      
      setDateTime(dateTime){	        
      	super._userInputValue = dateTime;
      	this.updateSelectTime();
      }
      
      
      updateSelectTime(){
      	this.hour = super._userInputValue.substr(11, 2);
      	this.minute = super._userInputValue.substr(14, 2);
      	
      	var h = parseInt(this.hour);
      	var m = parseInt(this.minute);
      	
      	this._changeTxtManual = true;
      	this._selectHour.options[h]

.selected = true;

      	this._selectMinute.options[m]

.selected = true;

      	this._changeTxtManual = false;
      }
  }
  	customElements.define(CustomDatePicker.is, CustomDatePicker);
```

server side :

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import com.vaadin.flow.component.ClientDelegate;
import com.vaadin.flow.component.Tag;
import com.vaadin.flow.component.datepicker.DatePicker;
import com.vaadin.flow.component.dependency.HtmlImport;


@Tag("custom-date-picker")
@HtmlImport("frontend://src/composants/CustomDatePicker.html")
public class CustomDatePicker extends DatePicker{
	private static final long serialVersionUID = 1L;

	public static String formatDay = "dd/MM/yyyy";
	public static String formatDayHour = "dd/MM/yyyy HH:mm";
	
	public static DateTimeFormatter patternDay = DateTimeFormatter.ofPattern(formatDay);
	public static DateTimeFormatter patterDayHour = DateTimeFormatter.ofPattern(formatDayHour);
	

	String dateTime = null;
	boolean time;
	
	
	public CustomDatePicker() {
		this(false);
	}
	
	public CustomDatePicker(boolean time) {
		setWidth("210px");
		
		if(time){			
			this.getElement().callFunction("_setTimeFeature");		
		}
	}
	
	public void setDateTime(String dateTime){	
		setValue(LocalDate.parse(dateTime.substring(0, 10), patternDay));
		
		if(dateTime.length() == formatDayHour.length()){
			this.getElement().callFunction("setDateTime", dateTime);
		}
		
		this.dateTime = dateTime;
	}
	
	public void setDateTime(LocalDateTime dateTime){
		setDateTime(dateTime.format(patterDayHour));
	}
	
	public String getDateTimeString(){
		return dateTime;
	}
	
	public LocalDateTime getDateTime(){
		return LocalDateTime.parse(dateTime, patterDayHour);
	}

	@ClientDelegate
	private void clientSetDateTime(String time){
		this.dateTime = time;				
	}
}

you can see the result in the attached image below

Time field not shown at all and I get this error in console:

Uncaught TypeError: Cannot read property ‘options’ of undefined
at HTMLElement.updateSelectTime (date-time-picker.html:188)

> this line: this._selectHour.options[h]

.selected = true;

Nemanja Kostic:

Alain HIRSCH:
This should be a standard feature of the vaadin component.
I hope it will be done in the future.

But if you want a quickly solution, i was working on this to train me on vaadin 10 and polymer.

i made a subclass to add the time feature to the vaadin date picker.

here is my code.
should work. But you will need to adapt for your use.
I used in french format (dd/mm/yyyy HH:mm)

client side :

<dom-module id="custom-date-picker"> 
	<template>
	</template> 
	<script>
      	class CustomDatePicker extends Vaadin.DatePickerElement  {
	        static get is() { return 'custom-date-picker'}
			
			static get template() {
				return Vaadin.DatePickerElement.template;
			}
			
	        static get observers() {
	        	return [
	              'textUpdateEvent(_userInputValue)'
	            ];
	     	}
	        	        
	        static get properties() {
	            return {
	              /**
	               * Set to false to disable this element.
	               */
	               showTime: {
	                type: Boolean,
	                value: true,
	                reflectToAttribute: true
	              },
	              hour: {
		                type: String,
		                value: '00',
		                reflectToAttribute: true
		              },
	              minute: {
		                type: String,
		                value: '00',
		                reflectToAttribute: true
		              },
		          _saveSelectedDate: {
		                type: Date
		              },
		          _selectHour: {
		                type: Object
		              },
		          _selectMinute: {
		                type: Object
		              },
	              _lastTime: {
		                type: String
		              }	,
	              _oldValue: {
		                type: String
		              },
	              _changeTxtManual: {
	                type: Boolean,
	                value: false
	              }
	            }
	        }
	        
	        _clear() {
	        	this._saveSelectedDate = null;
	        	super._clear();
	        }
	        
	        ready(){
	        	super.ready();
	        	
	        	//French
	        	super.set('i18n.firstDayOfWeek', 1);
	        	super.set('i18n.monthNames', ['Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Aout', 'Septembre', 'Octobre', 'Novembre', 'Décembre']

);

      	super.set('i18n.week', 'semaine');
      	super.set('i18n.weekdays', ['Dimanche', 'Lundi', 'Mardi', 'Mercredi', 'Jeudi', 'Vendredi', 'Samedi']

);

      	super.set('i18n.weekdaysShort', ['di','lu','ma','me','je','ve','sa']

);

      	super.set('i18n.calendar', 'calendrier');
      	super.set('i18n.clear', 'Effacer');
      	super.set('i18n.today', 'Aujourd\'hui');
      	super.set('i18n.cancel', 'Annuler');
      }
      
      
      _setTimeFeature(){
      	//Add time feature
      	var tmp = document.createElement('div');	
      	//TODO Put style in template
          tmp.innerHTML = '<div style="width: 120px;margin: auto;" class="cdp_TimeChooser"><select id="cdp_hour"></select>:<select id="cdp_minute"></select></div>';
          Polymer.dom(this.root).querySelector("vaadin-date-picker-overlay").root.querySelector("vaadin-date-picker-overlay-content").root.appendChild(tmp);
          
          this._selectHour = Polymer.dom(this.root).querySelector("vaadin-date-picker-overlay").root.querySelector("vaadin-date-picker-overlay-content").root.querySelector('#cdp_hour');
          this._selectMinute = Polymer.dom(this.root).querySelector("vaadin-date-picker-overlay").root.querySelector("vaadin-date-picker-overlay-content").root.querySelector('#cdp_minute');
          

          for(let i = 0; i < 24; i++){
          	var tmp_option = document.createElement('option');
          	tmp_option.innerHTML = '<option value="' + i + '">' + (i < 10 ? '0' + i :  i) + '</option>';
          	this._selectHour.append(tmp_option);
          }
          
          for(let i = 0; i < 60; i++){
          	var tmp_option = document.createElement('option');
          	tmp_option.innerHTML = '<option value="' + i + '">' + (i < 10 ? '0' + i :  i) + '</option>';
          	this._selectMinute.append(tmp_option);
          }
          
          
          //Events change
          this._selectHour.addEventListener('change', this._onHourChange.bind(this));
          this._selectMinute.addEventListener('change', this._onMinuteChange.bind(this));
      }
      	        
      _onHourChange(event){	
      	if(! this._changeTxtManual){
          	this.hour = event.target.value;	        	

          	if(this.showTime && super._userInputValue.length == 16){
          		super._userInputValue = super._userInputValue.substr(0, 11) + this.hour + ':' + super._userInputValue.substr(14,2);
          	}	     
      	}
      }
      
      _onMinuteChange(event){
      	if(! this._changeTxtManual){
          	this.minute = event.target.value;
          	
          	if(this.showTime && super._userInputValue.length == 16){
          		super._userInputValue = super._userInputValue.substr(0, 14) + this.minute;
          	}	
      	}
      }
      
      validate(value) {
      	value = value !== undefined ? value : this._inputValue;
      	
    	 	if(value.length > 10){
          	value = value.substr(0, 10);
          }
      	
      	if(this._saveSelectedDate){
      		super._selectedDate = this._saveSelectedDate;
      	}
      	else{
      		//Need to parse date here.
      		
      	}

          return super.validate(value);
      }
      
     textUpdateEvent(_userInputValue){		        	       		        	
      	//Time
      	if(this.showTime && _userInputValue.length == 10){
      		this._saveSelectedDate = super._selectedDate;
      		super._userInputValue = _userInputValue + ' ' + this.hour + ':' + this.minute;		
      	}
      	
      	if(this.showTime && super._userInputValue.length == 16 && (! this._lastTime  || this._lastTime !== super._userInputValue)){
      		this._lastTime = super._userInputValue;
      		this.$server.clientSetDateTime(super._userInputValue);
      		this.updateSelectTime();	        		
      	}		        	
      }
      
      setDateTime(dateTime){	        
      	super._userInputValue = dateTime;
      	this.updateSelectTime();
      }
      
      
      updateSelectTime(){
      	this.hour = super._userInputValue.substr(11, 2);
      	this.minute = super._userInputValue.substr(14, 2);
      	
      	var h = parseInt(this.hour);
      	var m = parseInt(this.minute);
      	
      	this._changeTxtManual = true;
      	this._selectHour.options[h]

.selected = true;

      	this._selectMinute.options[m]

.selected = true;

      	this._changeTxtManual = false;
      }
  }
  	customElements.define(CustomDatePicker.is, CustomDatePicker);
</script>
```

server side :

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import com.vaadin.flow.component.ClientDelegate;
import com.vaadin.flow.component.Tag;
import com.vaadin.flow.component.datepicker.DatePicker;
import com.vaadin.flow.component.dependency.HtmlImport;


@Tag("custom-date-picker")
@HtmlImport("frontend://src/composants/CustomDatePicker.html")
public class CustomDatePicker extends DatePicker{
	private static final long serialVersionUID = 1L;

	public static String formatDay = "dd/MM/yyyy";
	public static String formatDayHour = "dd/MM/yyyy HH:mm";
	
	public static DateTimeFormatter patternDay = DateTimeFormatter.ofPattern(formatDay);
	public static DateTimeFormatter patterDayHour = DateTimeFormatter.ofPattern(formatDayHour);
	

	String dateTime = null;
	boolean time;
	
	
	public CustomDatePicker() {
		this(false);
	}
	
	public CustomDatePicker(boolean time) {
		setWidth("210px");
		
		if(time){			
			this.getElement().callFunction("_setTimeFeature");		
		}
	}
	
	public void setDateTime(String dateTime){	
		setValue(LocalDate.parse(dateTime.substring(0, 10), patternDay));
		
		if(dateTime.length() == formatDayHour.length()){
			this.getElement().callFunction("setDateTime", dateTime);
		}
		
		this.dateTime = dateTime;
	}
	
	public void setDateTime(LocalDateTime dateTime){
		setDateTime(dateTime.format(patterDayHour));
	}
	
	public String getDateTimeString(){
		return dateTime;
	}
	
	public LocalDateTime getDateTime(){
		return LocalDateTime.parse(dateTime, patterDayHour);
	}

	@ClientDelegate
	private void clientSetDateTime(String time){
		this.dateTime = time;				
	}
}

you can see the result in the attached image below

Time field not shown at all and I get this error in console:

Uncaught TypeError: Cannot read property ‘options’ of undefined
at HTMLElement.updateSelectTime (date-time-picker.html:188)

this line: this._selectHour.options[h]
.selected = true;

Is it working code?

Unfortunately no.

What I was suggesting was something like this: https://vaadin-datetime-picker.glitch.me

![datetime-picker]
(https://www.dropbox.com/s/qc20kfs03oxpdug/datetime-picker.png?raw=1)

Source: https://glitch.com/edit/#!/vaadin-datetime-picker

Would that be good enough? Of course there should be an API to get/set a datetime value which proxies the internal field values (and all other field properties like required, invalid, error-message, etc.). I was lazy and didn’t implement that. I assume it would be straightforward.

(It’s Polymer 3 based, but easy to adapt to Polymer 2 if needed).

Thanks, this is good enough and styled nicely. Is source available somewhere, since you already did almost everything? Now I’m lazy :slight_smile:

It’s very strange dough that there is not yet official component. It’s usage is very common, used it many times in Vaadin 8 and previous versions. For example, when selecting date time range you expect to open one popup for ‘from’ and second one for ‘to’ not 4 selections (2 x date 2 x time)…

Added a link to the source in the previous message.

We wanted to do this, but we haven’t found the time yet. A lot of other priorities are getting in the way of many of these common UI components.

Thank you, this do well for now!

Wow. I wrote this code five month ago and the vaadin version was 10.0.0.beta8

A quick try to import this on the new vaadin version already discourage me.
@ClientDelegate annotation i used doesn’t exist anymore.

Alain HIRSCH:
Wow. I wrote this code five month ago and the vaadin version was 10.0.0.beta8

A quick try to import this on the new vaadin version already discourage me.
@ClientDelegate annotation i used doesn’t exist anymore.

@ClientDelegate is now @ClientCallable I think

Yes thank you i found it too.
I achieved to make it working with the latest vaadin 10 version with some change in my code.

here is the zip of a sample vaadin starter project. I just add the CustomDatePicker component in the header to test it.

Works for me.
But it’s for french date format, you will need to adapt for your use.

And for disclaimer, i am not using vaadin 10 for my development at he moment. In my work we will stick in older vaadin versions because we need internet explorer < 11 compatibility.
And i’m not sure vaadin 10 is enough mature to start a big project either.

This was just for training me and to see if it was possible to enhance an existing vaadin 10 component.

So prefer the official vaadin component when it will be released.

17368346.zip (93.8 KB)

Cool!
It would be good if it was a standard component.

Can you make him support Instant?

Who is this question addressed to? and what do you mean for instant ? The seconds ?

@Alain HIRSCH

I have Dto with field
Instant created;

Vaadin datepicker and you widget work with LocalDateTime

Ok.
You can easily convert a LocalDateTime to Instant.

You can modify the java class CustomDatePicker to override setValue() with an Instant parameter and add a getter that will you return an Instant.