Vaadin text field doesn't see value of 3rd party Date time range picker.

Hi there! I’m new in vaadin and I’m trying to develop my older project with vaadin. So I faced many issues with this [date time range picker]
(https://www.daterangepicker.com/) component.
I’m already know how to use this component in vaadin by importing javascript and style sheets see sample class below:

@StyleSheet("https://cdn.jsdelivr.net/npm/daterangepicker/daterangepicker.css")
@JavaScript("https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js")
@JavaScript("https://cdn.jsdelivr.net/momentjs/latest/moment.min.js")
@JavaScript("https://cdn.jsdelivr.net/npm/daterangepicker/daterangepicker.min.js")
//@JavaScript("./resources/static/js/test-jquery.js")
public class JqueryTestView extends VerticalLayout {
    private Button button = new Button("Open Modal");
    private H1 title = new H1("Test Page");
    private TextField textField = new TextField("Date-time");

    @PostConstruct
    public void init(){
        textField.setPlaceholder("click here");
        textField.setMinWidth("285px");
        textField.setId("daterange");

        button.addClickListener(click->{
            var textFieldDialog = new TextField("Date-time");
            textFieldDialog.setPlaceholder("click here");
            textFieldDialog.setMinWidth("285px");
            textFieldDialog.setId("daterange2");

            var window = new Dialog();
            window.add(textFieldDialog);
            window.setCloseOnOutsideClick(false);

            window.open();

            window.getElement().executeJs("$(function () {\n" +
                    "    $('#daterange2').daterangepicker({\n" +
                    "        timePicker: true,\n" +
                    "        timePicker24Hour: true,\n" +
                    "        timePickerIncrement: 5,\n" +
                    "        autoApply: true,\n" +
                    "        cancelLabel: 'Clear',\n" +
                    "        drops: 'auto'\n" +
                    "    }, function (start, end, label) {\n" +
                    "        const pattern = \"DD.MM.YYYY HH:mm\";\n" +
                    "        return start.format(pattern)+'-'+end.format(pattern);\n" +
                    "    });\n" +
                    "});").then(event -> {
                        Notification.show("AFTER EXECUTE JS : "+event.asString(), 3000, Notification.Position.BOTTOM_END);
            });
        });
        var button2 = new Button("GetValue");
        button2.addClickListener(click -> {
            Notification.show(textField.getValue(), 3000, Notification.Position.TOP_END);
        });
        add(title, button, textField, button2);
    }

    protected void onAttach(AttachEvent event) {
        super.onAttach(event);
        // executing JS should be avoided in constructor
        getElement().executeJs("$(function () {\n" +
                "    $('#daterange').daterangepicker({\n" +
                "        timePicker: true,\n" +
                "        timePicker24Hour: true,\n" +
                "        timePickerIncrement: 5,\n" +
                "        autoApply: true,\n" +
                "        cancelLabel: 'Clear',\n" +
                "        drops: 'auto'\n" +
                "    }, function (start, end, label) {\n" +
                "        const pattern = \"DD.MM.YYYY HH:mm\";\n" +
                "        $('#daterange').val(start.format(pattern)+'-'+end.format(pattern));\n" +
                "        return start.format(pattern)+'-'+end.format(pattern);\n" +
                "    });\n" +
                "});").then(e-> {
            Notification.show("AFTER EXECUTE JS : "+e.asString(), 3000, Notification.Position.BOTTOM_END);
        });
    }
    //"$('#daterange').find( \"input\" ).val(start.format('YYYY-MM-DD')+ ' ' +end.format('YYYY-MM-DD'))"+
}

, component appears and I know how to attach a value to picker, my problem is that even if visually value is inside a text field, actually if try to get a value it will be null. Unfortunately I’m not able to attach screen shots here, but I can share [link to github]
(https://github.com/code-6/tourManager.git) project where you can checkout “rf_new-add-tour-form”, run project, navigate to http://localhost:9105/tours and press on add button. Then new form will appears and by pressing on a “date-time” field picker will appears. Then you can choose a date and value will be inside field, but after press save, date will be null. This is because I’m setting value through javascript.

$(document).ready(function () {
    $('#daterange').daterangepicker({
            timePicker: true,
            timePicker24Hour: true,
            timePickerIncrement: 5,
            autoApply: true,
            cancelLabel: 'Clear'
        }, function (start, end, label) {
            const pattern = "DD.MM.YYYY HH:mm";
            $('#daterange').val(start.format(pattern) + '-' + end.format(pattern));
        });
});

And a text field component have id “daterange” date.setId("daterange");
In attachments you can find screenshots of how how it looks like and log with empty date.
Please help me to resolve this issue.

I already created another threads ([thread]
(https://vaadin.com/forum/thread/18307184/dialog-bootstrap-datetimerangepicker-appearance-problem)) this is also related to this 3rd party component.

18324680.png
18324683.png

Perhaps I’m missing something, but as far as I can tell, you are developing a Vaadin 14.1.25 app, while the [Bootstrap DateTimeRangePicker Add-on]
(https://vaadin.com/directory/component/bootstrap-datetimerangepicker-add-on/overview) that you are using is only supported Vaadin 7 & 8. You might want to search the Directory for other addons that are supported for V10+ (for example, [this one]
(https://vaadin.com/directory/component/daterange-picker)). Alternatively, you might wish to integrate the date-range-picker component yourself by following the steps outlined in the docs: https://vaadin.com/docs/v14/flow/web-components/integrating-a-web-component.html

Tarek Oraby:
Perhaps I’m missing something, but as far as I can tell, you are developing a Vaadin 14.1.25 app, while the [Bootstrap DateTimeRangePicker Add-on]
(https://vaadin.com/directory/component/bootstrap-datetimerangepicker-add-on/overview) that you are using is only supported Vaadin 7 & 8. You might want to search the Directory for other addons that are supported for V10+ (for example, [this one]
(https://vaadin.com/directory/component/daterange-picker)). Alternatively, you might wish to integrate the date-range-picker component yourself by following the steps outlined in the docs: https://vaadin.com/docs/v14/flow/web-components/integrating-a-web-component.html

Hi Tarek Oraby I already know that vaadin add-on is not supported by vaadin 14. This add-on was my first try to use this picker in my app. After facing an failure I created a [thread]
(https://vaadin.com/forum/thread/18249009/how-to-use-bootstrap-datetimerangepicker-add-on) where i found that for 14th version I’ll not able to use it as add-on, but I got alternative way to use picker. I’m not using vaadin add-on. Possibly it is my mistake that i not attached some more code. I’m using import of javascript and style sheet instead of add-on. Thank you for your reply, I’ll modify my question.

Stanislav Wong:
Hi there! I’m new in vaadin and I’m trying to develop my older project with vaadin. So I faced many issues with this [date time range picker]
(https://www.daterangepicker.com/) component.
I’m already know how to use this component in vaadin by importing javascript and style sheets see sample class below:

@StyleSheet("https://cdn.jsdelivr.net/npm/daterangepicker/daterangepicker.css")
@JavaScript("https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js")
@JavaScript("https://cdn.jsdelivr.net/momentjs/latest/moment.min.js")
@JavaScript("https://cdn.jsdelivr.net/npm/daterangepicker/daterangepicker.min.js")
//@JavaScript("./resources/static/js/test-jquery.js")
public class JqueryTestView extends VerticalLayout {
    private Button button = new Button("Open Modal");
    private H1 title = new H1("Test Page");
    private TextField textField = new TextField("Date-time");

    @PostConstruct
    public void init(){
        textField.setPlaceholder("click here");
        textField.setMinWidth("285px");
        textField.setId("daterange");

        button.addClickListener(click->{
            var textFieldDialog = new TextField("Date-time");
            textFieldDialog.setPlaceholder("click here");
            textFieldDialog.setMinWidth("285px");
            textFieldDialog.setId("daterange2");

            var window = new Dialog();
            window.add(textFieldDialog);
            window.setCloseOnOutsideClick(false);

            window.open();

            window.getElement().executeJs("$(function () {\n" +
                    "    $('#daterange2').daterangepicker({\n" +
                    "        timePicker: true,\n" +
                    "        timePicker24Hour: true,\n" +
                    "        timePickerIncrement: 5,\n" +
                    "        autoApply: true,\n" +
                    "        cancelLabel: 'Clear',\n" +
                    "        drops: 'auto'\n" +
                    "    }, function (start, end, label) {\n" +
                    "        const pattern = \"DD.MM.YYYY HH:mm\";\n" +
                    "        return start.format(pattern)+'-'+end.format(pattern);\n" +
                    "    });\n" +
                    "});").then(event -> {
                        Notification.show("AFTER EXECUTE JS : "+event.asString(), 3000, Notification.Position.BOTTOM_END);
            });
        });
        var button2 = new Button("GetValue");
        button2.addClickListener(click -> {
            Notification.show(textField.getValue(), 3000, Notification.Position.TOP_END);
        });
        add(title, button, textField, button2);
    }

    protected void onAttach(AttachEvent event) {
        super.onAttach(event);
        // executing JS should be avoided in constructor
        getElement().executeJs("$(function () {\n" +
                "    $('#daterange').daterangepicker({\n" +
                "        timePicker: true,\n" +
                "        timePicker24Hour: true,\n" +
                "        timePickerIncrement: 5,\n" +
                "        autoApply: true,\n" +
                "        cancelLabel: 'Clear',\n" +
                "        drops: 'auto'\n" +
                "    }, function (start, end, label) {\n" +
                "        const pattern = \"DD.MM.YYYY HH:mm\";\n" +
                "        $('#daterange').val(start.format(pattern)+'-'+end.format(pattern));\n" +
                "        return start.format(pattern)+'-'+end.format(pattern);\n" +
                "    });\n" +
                "});").then(e-> {
            Notification.show("AFTER EXECUTE JS : "+e.asString(), 3000, Notification.Position.BOTTOM_END);
        });
    }
    //"$('#daterange').find( \"input\" ).val(start.format('YYYY-MM-DD')+ ' ' +end.format('YYYY-MM-DD'))"+
}

, component appears and I know how to attach a value to picker, my problem is that even if visually value is inside a text field, actually if try to get a value it will be null. Unfortunately I’m not able to attach screen shots here, but I can share [link to github]
(https://github.com/code-6/tourManager.git) project where you can checkout “rf_new-add-tour-form”, run project, navigate to http://localhost:9105/tours and press on add button. Then new form will appears and by pressing on a “date-time” field picker will appears. Then you can choose a date and value will be inside field, but after press save, date will be null. This is because I’m setting value through javascript.

$(document).ready(function () {
    $('#daterange').daterangepicker({
            timePicker: true,
            timePicker24Hour: true,
            timePickerIncrement: 5,
            autoApply: true,
            cancelLabel: 'Clear'
        }, function (start, end, label) {
            const pattern = "DD.MM.YYYY HH:mm";
            $('#daterange').val(start.format(pattern) + '-' + end.format(pattern));
        });
});

And a text field component have id “daterange” date.setId("daterange");
In attachments you can find screenshots of how how it looks like and log with empty date.
Please help me to resolve this issue.

I already created another threads ([thread]
(https://vaadin.com/forum/thread/18307184/dialog-bootstrap-datetimerangepicker-appearance-problem)) this is also related to this 3rd party component.

Seems I found how to avoid this problems. So I found how to get value from field using javascript;

return $('#daterange').val()

I just execute script above on save button press this will return me a value, then I can use setValue method on field component like this:

saveButton.addClickListener(click -> {

            getElement().executeJs("return $('#daterange').val()").then(e -> {
                System.out.println(e.toJson());
                textField.setValue(e.toJson().replaceAll("\"", ""));
                Notification.show("VALUE IN FIELD: " + textField.getValue(), 3000, Notification.Position.BOTTOM_START);
            });
        });

But this is bad solution, I’m not solving problem, only avoid. Also it will works only if this is used inside method that has @PostConsturct annotation. Inside constructor this not works. I tried to use this in my test view “JqueryTestView”, where I’m using @PostConstruct and it works, but same not works for “AddTourForm”

By default, the value of the Java component Vaadin TextField is synchronized ON_CHANGE. In your case, the client side will never send the on_change event so the value is not reflected in the Java side.

One solution is to add this line:

textField.setValueChangeMode(ValueChangeMode.EAGER);

You should avoid $('#daterange') because id should be unique in your page. As a replacement you can do this:

@StyleSheet("https://cdn.jsdelivr.net/npm/daterangepicker/daterangepicker.css")
@JavaScript("https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js")
@JavaScript("https://cdn.jsdelivr.net/momentjs/latest/moment.min.js")
@JavaScript("https://cdn.jsdelivr.net/npm/daterangepicker/daterangepicker.min.js")
public class DateRangeTextField extends TextField {

    public DateRangeTextField() {
        this("");
    }

    public DateRangeTextField(String label) {
        super(label);
        setValueChangeMode(ValueChangeMode.EAGER);
    }

    protected void onAttach(AttachEvent event) {
        super.onAttach(event);
        // executing JS should be avoided in constructor
        getElement().executeJs(
                "    $($0).daterangepicker({\n" +
                "        timePicker: true,\n" +
                "        timePicker24Hour: true,\n" +
                "        timePickerIncrement: 5,\n" +
                "        autoApply: true,\n" +
                "        cancelLabel: 'Clear',\n" +
                "        drops: 'auto'\n" +
                "    }, function (start, end, label) {\n" +
            "        const pattern = \"DD.MM.YYYY HH:mm\";\n" +
                    "        $0.value = start.format(pattern)+'-'+end.format(pattern);\n" +
                    "        return start.format(pattern)+'-'+end.format(pattern);\n" +
                    "    });", getElement());
    }
}

About the dialog issue it’s harder to find a workaround.
Why this is happening?
The calendar added by jquery is not inside the dialog, when you click in the calendar (outside the dialog), you will lose the focus of the text field (because you clicked outside the dialog), when you leave the input jquery is closing the calendar.
One solution is to add the daterangepicker from jquery inside the dialog (parentEl option) but the dialog overlay is inside shadow dom and jquery does not work very well with shadow dom.

So if you need to use a daterange picker inside a dialog, you probably need to find another daterangepicker.

Stanislav Wong:

Stanislav Wong:
Hi there! I’m new in vaadin and I’m trying to develop my older project with vaadin. So I faced many issues with this [date time range picker]
(https://www.daterangepicker.com/) component.
I’m already know how to use this component in vaadin by importing javascript and style sheets see sample class below:

@StyleSheet("https://cdn.jsdelivr.net/npm/daterangepicker/daterangepicker.css")
@JavaScript("https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js")
@JavaScript("https://cdn.jsdelivr.net/momentjs/latest/moment.min.js")
@JavaScript("https://cdn.jsdelivr.net/npm/daterangepicker/daterangepicker.min.js")
//@JavaScript("./resources/static/js/test-jquery.js")
public class JqueryTestView extends VerticalLayout {
    private Button button = new Button("Open Modal");
    private H1 title = new H1("Test Page");
    private TextField textField = new TextField("Date-time");

    @PostConstruct
    public void init(){
        textField.setPlaceholder("click here");
        textField.setMinWidth("285px");
        textField.setId("daterange");

        button.addClickListener(click->{
            var textFieldDialog = new TextField("Date-time");
            textFieldDialog.setPlaceholder("click here");
            textFieldDialog.setMinWidth("285px");
            textFieldDialog.setId("daterange2");

            var window = new Dialog();
            window.add(textFieldDialog);
            window.setCloseOnOutsideClick(false);

            window.open();

            window.getElement().executeJs("$(function () {\n" +
                    "    $('#daterange2').daterangepicker({\n" +
                    "        timePicker: true,\n" +
                    "        timePicker24Hour: true,\n" +
                    "        timePickerIncrement: 5,\n" +
                    "        autoApply: true,\n" +
                    "        cancelLabel: 'Clear',\n" +
                    "        drops: 'auto'\n" +
                    "    }, function (start, end, label) {\n" +
                    "        const pattern = \"DD.MM.YYYY HH:mm\";\n" +
                    "        return start.format(pattern)+'-'+end.format(pattern);\n" +
                    "    });\n" +
                    "});").then(event -> {
                        Notification.show("AFTER EXECUTE JS : "+event.asString(), 3000, Notification.Position.BOTTOM_END);
            });
        });
        var button2 = new Button("GetValue");
        button2.addClickListener(click -> {
            Notification.show(textField.getValue(), 3000, Notification.Position.TOP_END);
        });
        add(title, button, textField, button2);
    }

    protected void onAttach(AttachEvent event) {
        super.onAttach(event);
        // executing JS should be avoided in constructor
        getElement().executeJs("$(function () {\n" +
                "    $('#daterange').daterangepicker({\n" +
                "        timePicker: true,\n" +
                "        timePicker24Hour: true,\n" +
                "        timePickerIncrement: 5,\n" +
                "        autoApply: true,\n" +
                "        cancelLabel: 'Clear',\n" +
                "        drops: 'auto'\n" +
                "    }, function (start, end, label) {\n" +
                "        const pattern = \"DD.MM.YYYY HH:mm\";\n" +
                "        $('#daterange').val(start.format(pattern)+'-'+end.format(pattern));\n" +
                "        return start.format(pattern)+'-'+end.format(pattern);\n" +
                "    });\n" +
                "});").then(e-> {
            Notification.show("AFTER EXECUTE JS : "+e.asString(), 3000, Notification.Position.BOTTOM_END);
        });
    }
    //"$('#daterange').find( \"input\" ).val(start.format('YYYY-MM-DD')+ ' ' +end.format('YYYY-MM-DD'))"+
}

, component appears and I know how to attach a value to picker, my problem is that even if visually value is inside a text field, actually if try to get a value it will be null. Unfortunately I’m not able to attach screen shots here, but I can share [link to github]
(https://github.com/code-6/tourManager.git) project where you can checkout “rf_new-add-tour-form”, run project, navigate to http://localhost:9105/tours and press on add button. Then new form will appears and by pressing on a “date-time” field picker will appears. Then you can choose a date and value will be inside field, but after press save, date will be null. This is because I’m setting value through javascript.

$(document).ready(function () {
    $('#daterange').daterangepicker({
            timePicker: true,
            timePicker24Hour: true,
            timePickerIncrement: 5,
            autoApply: true,
            cancelLabel: 'Clear'
        }, function (start, end, label) {
            const pattern = "DD.MM.YYYY HH:mm";
            $('#daterange').val(start.format(pattern) + '-' + end.format(pattern));
        });
});

And a text field component have id “daterange” date.setId("daterange");
In attachments you can find screenshots of how how it looks like and log with empty date.
Please help me to resolve this issue.

I already created another threads ([thread]
(https://vaadin.com/forum/thread/18307184/dialog-bootstrap-datetimerangepicker-appearance-problem)) this is also related to this 3rd party component.

Seems I found how to avoid this problems. So I found how to get value from field using javascript;

return $('#daterange').val()

I just execute script above on save button press this will return me a value, then I can use setValue method on field component like this:

saveButton.addClickListener(click -> {

            getElement().executeJs("return $('#daterange').val()").then(e -> {
                System.out.println(e.toJson());
                textField.setValue(e.toJson().replaceAll("\"", ""));
                Notification.show("VALUE IN FIELD: " + textField.getValue(), 3000, Notification.Position.BOTTOM_START);
            });
        });

But this is bad solution, I’m not solving problem, only avoid. Also it will works only if this is used inside method that has @PostConsturct annotation. Inside constructor this not works. I tried to use this in my test view “JqueryTestView”, where I’m using @PostConstruct and it works, but same not works for “AddTourForm”

So I maked it works. I’m executing following code each time when save button in AddTourForm is pressed:

 saveButton.addClickListener(e -> {

            UI.getCurrent().getPage().executeJs("return $('#daterange').val()").then(res -> {
                String r = res.toJson();
                r = r.replaceAll("\"", "");
                date.setValue(r);
                if (validateAndSave())
                    Notification.show("Saved successfully", 2000, Notification.Position.TOP_END);
                else
                    Notification.show("Save failed", 2000, Notification.Position.TOP_END);
            });
        });

But still I think this is not best solution. If some one knows how to resolve this in another way please let me know. Thanks a lot for your atention.

Hi, did you try my solution?

Jean-Christophe Gueriaud:
Hi, did you try my solution?

Hi Jean-Christophe! Thanks a lot for your reply! Yes I tried your solution also and it works, value is there, but I faced next issue, if make field read-only value will set-up and then gone ). I have no idea why it happens.
I just created new class and extend it from TextField as you shown. After that I removed all JS execution in other places and removed using of setReadOnly method, after that it works as expected. With read-only it has strange behaviour. I pushed new branch “ft_refactor-picker-usage” with your solution to [github]
(https://github.com/code-6/tourManager.git). You can try it with and without read-only to see what happens.

From the documentation of setReadonly:
Sets the read-only mode of this {@code HasValue} to given mode. The user can’t change the value when in read-only mode.

That’s why the value is not changed. (I think the vaadn-textfield blocks user changes)

You can try to use Input instead of TextField, I really don’t know what are the consequences of using jquery-datepicker inside a vaadin-textfield.