Dialog Bypass on Rapid Increment/Decrement Clicks with Stimulus
AdamMusa opened this issue · 0 comments
AdamMusa commented
When rapidly clicking the increment or decrement buttons, the dialog intended to appear based on specific countValue conditions (10 or -3) sometimes fails to show as expected.
To Reproduce the Bug
- Copy and paste the provided code into your project.
- Run the application.
- Rapidly click the increment or decrement button to observe the dialog behavior.
import { Controller } from "@hotwired/stimulus"
// Connects to data-controller="counter"
export default class extends Controller {
static targets = ['count','showDialog']
static values = {count: Number,active: Boolean}
connect() {
this.countValue = 0
this.activeValue = false;
this.updateCount()
this.showDialog()
}
increment(){
this.countValue++
this.updateCount()
this.showDialog()
}
decrement(){
this.countValue--
this.updateCount()
this.showDialog()
}
updateCount(){
this.countTarget.textContent = this.countValue
}
showDialog(){
this.activeValue = (this.countValue == 10 || this.countValue == -3)
if(this.activeValue) this.showDialogTarget.classList.remove('hidden')
}
showDialog() {
const shouldShowDialog = (this.countValue === 10 || this.countValue === -3);
if (shouldShowDialog) {
this.showDialogTarget.classList.remove('hidden');
setTimeout(() => {
this.showDialogTarget.classList.remove('opacity-0', 'pointer-events-none');
this.showDialogTarget.classList.add('opacity-100');
}, 10); // Delay to ensure class removal is processed
} else {
this.showDialogTarget.classList.remove('opacity-100');
this.showDialogTarget.classList.add('opacity-0');
setTimeout(() => {
this.showDialogTarget.classList.add('hidden');
this.showDialogTarget.classList.remove('pointer-events-none');
}, 300); // Duration of the fade-out animation
}
}
closeDialog() {
this.countValue = 0;
this.countTarget.textContent = 0;
// Add move-left class for the animation
this.showDialogTarget.classList.add('move-left');
setTimeout(() => {
this.showDialogTarget.classList.add('hidden');
this.showDialogTarget.classList.remove('pointer-events-none');
// Remove the move-left class to reset for future openings
this.showDialogTarget.classList.remove('move-left');
}, 300); // Duration of the animation
}
}
this is my view code
<div data-controller="counter" class="w-full h-full">
<!-- Increment button with multiple actions -->
<button data-action="click->counter#increment mouseover->counter#increment">Increment</button>
<!-- Display count value -->
<p data-counter-target="count"></p>
<!-- Decrement button -->
<button data-action="click->counter#decrement">Decrement</button>
<!-- Dialog element with data-controller-target -->
<!-- Dialog element with data-controller-target -->
<div data-counter-target="showDialog" class="fixed inset-0 flex items-center justify-center z-50 opacity-0 pointer-events-none transition-opacity duration-300 ease-out hidden">
<div class="bg-black bg-opacity-70 p-6 shadow-lg w-full h-full flex items-center justify-center">
<div class="bg-white p-6 rounded-lg max-w-4xl w-full">
<h2 class="text-black text-xl font-semibold mb-4">Dialog Title</h2>
<p class="text-black mb-4">This is the content of the dialog card. You can add more text or HTML here.</p>
<button data-action="click->counter#closeDialog" class="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600">
Close
</button>
</div>
</div>
</div>
</div>
<div data-controller="home">
<div data-home-target="change">
</div>
<h1 class="font-bold text-4xl" data-action="click->home#open">Home#index</h1>
<p data-action="click->home#replace">Find me in app/views/home/index.html.erb</p>
</div>
Expected Behavior
The dialog should consistently appear when countValue is 10 or -3 in my case, and disappear otherwise, regardless of how quickly the increment or decrement buttons are clicked.