flowbite icon indicating copy to clipboard operation
flowbite copied to clipboard

Input tag value updated by Flowbite datepicker doesn't trigger phx-change="validate"

Open puruzio opened this issue 2 years ago • 12 comments

Describe the bug When I select a date from the datepicker, the selected date shows in the date input box as text, but the "validate" event is not fired. The following is my related code based on Flowbite documentation (https://flowbite.com/docs/getting-started/phoenix/)

Hooks.Datepicker = {
  mounted() {
      const datepickerEl = this.el;
      new Datepicker(datepickerEl, {
        autohide: true,
        format: 'yyyy-mm-dd',
      });
  },
  updated() {
      this.mounted();
  }
}

To Reproduce Steps to reproduce the behavior:

  1. Add the datepicker to a form that defines phx-change="validate" in a Phoenix project based on the documentation (https://flowbite.com/docs/getting-started/phoenix/)
  2. Click on a date on the datepicker
  3. Notice the "validate" event is not fired.

Expected behavior Step 3 of the Reproduce step should trigger "validate" event

Screenshots

Desktop (please complete the following information):

  • OS: [e.g. iOS] Windows 11
  • Browser [e.g. chrome, safari] Chrome, Firefox, Edge
  • Version [e.g. 22]

Additional context

puruzio avatar Nov 21 '23 17:11 puruzio

@jmnda-dev I see you have contributed a lot to this project for Phoenix Liveview integration. Can you please shed some lights on what my issue might be caused by? Thanks.

puruzio avatar Nov 21 '23 17:11 puruzio

EDIT: Commented from wrong account

@jmnda-dev I see you have contributed a lot to this project for Phoenix Liveview integration. Can you please shed some lights on what my issue might be caused by? Thanks.

Hmm 🤔, I will have a look once I settle down

jmnda-dev avatar Nov 21 '23 20:11 jmnda-dev

@jmnda-dev Just to share my findings. I tried addEventListener("changeDate"..) like the following, and it does trigger phx-change. However, it seems to cause LV to go into some kind of loop showing gradually more repetition of (phx-F5oyNZEPzdxLLwPl update: - {8: 1, 10: {…}}... ) as I click on the datepicker more.

According to what Chris McCord said here (https://elixirforum.com/t/triggering-liveview-form-change-event-from-javascript/37073/2), this looks like it should work, but I can't quite get it to work.

Any pointers will be appreciated. Thanks.

Hooks.Datepicker = {
  mounted() {
      const datepickerEl = this.el;
      new Datepicker(datepickerEl, {
        autohide: true,
        format: 'yyyy-mm-dd',
      });

      this.el.addEventListener("changeDate", e => {
        let event = new Event("change", {bubbles: true});
        this.el.dispatchEvent(event);
      })

puruzio avatar Nov 23 '23 08:11 puruzio

Also tried modifying Datepicker.js like this, but it still didn't trigger phx-change.

  if (newDates.toString() !== datepicker.dates.toString()) {
    datepicker.dates = newDates;
    refreshUI(datepicker, render ? 3 : 1);
    triggerDatepickerEvent(datepicker, 'input');  /// changed from 'changeDate' to 'input' (and also tried 'change') hoping that phx-change will pick up on it.

puruzio avatar Nov 23 '23 08:11 puruzio

@puruzio Hi sorry for taking decades to respond 😁️ have been a bit busy. I haven't managed to get it to work. I am still investigating the issue though. I even tried to modify the Datepicker plugin to initialize on phx:page-loading-stop event emitted by liveview, but that didn't work.I will contitue to share my findings for a working solution.

jmnda-dev avatar Nov 23 '23 14:11 jmnda-dev

@puruzio So I tested the code you shared for triggering form change events from Javascript and it's working for me:

Hooks.Datepicker = {
    mounted() {
        const datepickerEl = this.el;
        new Datepicker(datepickerEl, {
        format: 'yyyy-mm-dd',
        autohide: true
        });
        this.el.addEventListener("changeDate", e => {
            console.log("Changed")
            let event = new Event("change", {bubbles: true});
            this.el.dispatchEvent(event);
        })
    },
}

Versions:

  • {:phoenix, "~> 1.7.10"}
  • {:phoenix_live_view, "~> 0.20.1"}
  • flowbite@^2.0.0
  • flowbite-datepicker@^1.2.4

I let me know if it works for you.

jmnda-dev avatar Nov 23 '23 15:11 jmnda-dev

@jmnda-dev Happy Thanksgiving! Thank you for taking time to look into this.

As you can see in this screen capture video, I face a few issues.

  1. The date picker doesn't auto-hide despite the autohide: true that is set.
  2. Browser console shows the update cycle repeated increasingly more times as I click on dates.
  3. The update doesn't seem to take effect on the UI until the next date selection is made. The video shows how a new log is added at the bottom of the screen only after the next date is clicked.

https://github.com/themesberg/flowbite/assets/1150766/2ff64fb9-fbdf-49b8-8f6e-9a7f30fe218e

puruzio avatar Nov 23 '23 16:11 puruzio

@puruzio Everything is working fine on my side. Would you like I share my demo app? datepicker-demo

jmnda-dev avatar Nov 25 '23 10:11 jmnda-dev

@jmnda-dev Yes. That will be great. Thank you!!

puruzio avatar Nov 26 '23 00:11 puruzio

@puruzio I have created a demo repo here: https://github.com/jmnda-dev/liveview-flowbite-datepicker-demo

You will notice that the form on the Post listing page is not put in a modal, you are able to use the datepicker. However on the Post detail page, the edit form is in a modal. If you click on the Date Published input, the datepicker is not showing probably because the z-index of the datepicker is lower than that of the modal and other elements on the page. So on the edit form modal on the detail page, click on the Date Published input. the datepicker won't show, then in your browser inspector search for the element with this this class datepicker datepicker-dropdown dropdown absolute top-0 left-0 z-20 pt-2 active block datepicker-orient-top datepicker-orient-left then adjust its z-index(set it higher) and you will see it will show up and you can select dates and the change events are pushed to the server.

jmnda-dev avatar Nov 26 '23 18:11 jmnda-dev

@jmnda-dev Thank you! Much appreciated!

puruzio avatar Nov 26 '23 18:11 puruzio

@puruzio Perhaps an improvement to that could be made to flowbite-datepicker is to allow the overriding of Tailwind CSS classes for the datepicker because a page might have different elements with varying z-index values, which might cause the datepicker to not work propery. Not sure about this though, just a thought.

jmnda-dev avatar Nov 26 '23 18:11 jmnda-dev

One thing to point out in this thread. The date-picker integration guide is flawed: do not call this.mounted(); inside updated callback, as this will initialize the component multiple times. This could work only if you change mounted to st:

 mounted() {
      if(this.initialized) return;
      this.initialized = true;

      const datepickerEl = this.el;
      new Datepicker(datepickerEl, {
        autohide: true,
        format: 'yyyy-mm-dd',
      });
  },

unematiii avatar Jun 04 '24 16:06 unematiii

Hey everyone,

I've got some good news - since v2.4.1 the datepicker is now a core component of the Flowbite JS.

That means that everything related to instances, initialization are now ported via the main Instance Manager.

For frameworks like Phoenix you no longer need to separately install the datepicker file/plugin:

https://flowbite.com/docs/components/datepicker/#javascript-behaviour

More on this here:

https://flowbite.com/docs/getting-started/phoenix/#datepicker-plugin

Cheers, Zoltan

zoltanszogyenyi avatar Jun 27 '24 10:06 zoltanszogyenyi

Hey everyone,

I've got some good news - since v2.4.1 the datepicker is now a core component of the Flowbite JS.

That means that everything related to instances, initialization are now ported via the main Instance Manager.

Awesome 🎉️

jmnda-dev avatar Jul 23 '24 18:07 jmnda-dev

One thing to point out in this thread. The date-picker integration guide is flawed: do not call this.mounted(); inside updated callback, as this will initialize the component multiple times. This could work only if you change mounted to st:

 mounted() {
      if(this.initialized) return;
      this.initialized = true;

      const datepickerEl = this.el;
      new Datepicker(datepickerEl, {
        autohide: true,
        format: 'yyyy-mm-dd',
      });
  },

Yeah that makes sense

jmnda-dev avatar Jul 23 '24 18:07 jmnda-dev