themesberg / flowbite

Open-source UI component library and front-end development framework based on Tailwind CSS
https://flowbite.com
MIT License
7.74k stars 727 forks source link

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

Closed puruzio closed 3 months ago

puruzio commented 10 months ago

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):

Additional context

puruzio commented 10 months ago

@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.

jmnda-dev commented 10 months ago

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

puruzio commented 10 months ago

@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 commented 10 months ago

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.
jmnda-dev commented 10 months ago

@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 commented 10 months ago

@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:

I let me know if it works for you.

puruzio commented 10 months ago

@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

jmnda-dev commented 10 months ago

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

puruzio commented 10 months ago

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

jmnda-dev commented 10 months ago

@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.

puruzio commented 10 months ago

@jmnda-dev Thank you! Much appreciated!

jmnda-dev commented 10 months ago

@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.

unematiii commented 4 months ago

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',
      });
  },
zoltanszogyenyi commented 3 months ago

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

jmnda-dev commented 2 months ago

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 commented 2 months ago

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