Tengo una ventana modal para filtros en mi aplicación. El modal de filtros tiene @click.outside="filters = false" , por lo que si el usuario hace clic fuera del modal, se ocultará. Dentro de ese modal de filtros, tengo una opción para elegir la fecha mínima para la que estoy usando Flatpickr.
El problema es que cuando hace clic en las flechas para cambiar el mes, o el mes o el año en la parte superior, los filtros modales se ocultarán.
Creo que necesito usar e.stopPropagation o @click.prevent en el elemento, pero no funcionó en todos los lugares en los que lo probé.
¿Cómo hago para que los clics dentro de la ventana de Flatpicker no se propaguen y cierren los filtros modales?
Aquí está mi código completo:
<div x-show="filters" @click.outside="filters = false" x-on:keydown.escape.window="filters = false" class="absolute shadow-lg z-40 mt-4"> <div x-trap="filters"> <div> <label for="filter-date-min" class="block text-sm font-semibold leading-5 text-gray-700">Minimum Date</label> <div class="mt-1 relative rounded-md shadow-sm"> <div x-data="{ value: '', init() { let picker = flatpickr(this.$refs.picker, { dateFormat: 'Ym-d', defaultDate: this.value, onChange: (date, dateString) => { this.value = dateString }, }) }, }"> <input id="filter-date-min" placeholder="MM/DD/YYYY" x-ref="picker" x-bind:value="value" class="flex-1 min-w-0 block w-full px-3 py-2 rounded-none rounded-r-md focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm border-gray-300 border active" autocomplete="off"> </div> </div> </div> </div> </div>Una solución simple para este problema es introducir una variable pickerOpen que monitorea el estado de la ventana emergente Flatpickr a través de los ganchos onOpen y onClose . Luego, solo cierre la ventana modal cuando la ventana emergente Flatkpickr esté inactiva.
<div x-data="{filters: false, pickerOpen: false}"> <div x-show="filters" @click.outside="if (!pickerOpen) {filters = false}" x-on:keydown.escape.window="if (!pickerOpen) {filters = false}" class="absolute shadow-lg z-40 mt-4"> <div x-trap="filters"> <div> <label for="filter-date-min" class="block text-sm font-semibold leading-5 text-gray-700">Minimum Date</label> <div class="mt-1 relative rounded-md shadow-sm"> <div x-data="{ value: '', init() { let picker = flatpickr(this.$refs.picker, { dateFormat: 'Ym-d', defaultDate: this.value, onOpen: () => {this.pickerOpen = true}, onClose: () => {this.pickerOpen = false}, onChange: (date, dateString) => { this.value = dateString }, }) }, }"> <input id="filter-date-min" placeholder="MM/DD/YYYY" x-ref="picker" x-bind:value="value" autocomplete="off" class="flex-1 min-w-0 block w-full px-3 py-2 rounded-none rounded-r-md focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm border-gray-300 border active"> </div> </div> </div> </div> </div> </div>No creo que AlpineJS sea capaz de hacer esto, por lo que puede agregar un JS personalizado. Puede agregar este código en una etiqueta de secuencia de comandos justo antes de la etiqueta del cuerpo de cierre:
[...document.getElementsByClassName("flatpickr-calendar")].forEach($el => { $el.addEventListener("click", e => e.stopPropagation()); });Una vez que el usuario abre una ventana emergente de Flatpickr, Flatpickr agrega el calendario al final del cuerpo , no dentro de su div, por lo que es un clic "externo".
AlpineJS determina los clics "externos" al agregar un detector de eventos a la window (o algo similar), y cuando el evento se propaga (se propaga), prueba si el destino del clic es el elemento que solicita un clic externo. De lo contrario, activa un evento de que hay un clic "externo".
Lo que hace esencialmente este código es que, una vez que se hace clic en un calendario emergente de Flatpickr, evitamos que el evento aparezca en AlpineJS, por lo que Alpine no sabe que hubo ningún clic en la ventana, por lo que ganó @click.outside No se activa cuando se hace clic en el calendario.