166 lines
6.0 KiB
Markdown
166 lines
6.0 KiB
Markdown
# Shot Delete Event Bubbling - Final Fix
|
|
|
|
## Issue Description
|
|
|
|
The shot detail panel was still being triggered when performing delete shot actions, despite previous attempts to fix event bubbling. This was happening because the event prevention logic in the `handleRowClick` function was not comprehensive enough to catch all interactive elements within the dropdown menu.
|
|
|
|
## Root Cause Analysis
|
|
|
|
The issue occurred in the `ShotsDataTable.vue` component where the `handleRowClick` function was not properly detecting all types of interactive elements that should prevent row click events. Specifically:
|
|
|
|
1. **Incomplete Element Detection**: The original selector list was missing some Radix UI specific attributes and SVG icons
|
|
2. **Missing Parent Element Traversal**: The function wasn't checking parent elements for event handlers
|
|
3. **Icon Click Events**: SVG icons within buttons were not being properly detected
|
|
4. **Radix UI Elements**: Some Radix UI dropdown elements have dynamic attributes that weren't being caught
|
|
|
|
## Solution Implementation
|
|
|
|
### 1. Enhanced Interactive Element Detection
|
|
|
|
Updated the `handleRowClick` function in `ShotsDataTable.vue` to include a more comprehensive list of selectors:
|
|
|
|
```typescript
|
|
const isInteractiveElement = target.closest([
|
|
'button',
|
|
'[role="menuitem"]',
|
|
'[role="menu"]',
|
|
'[data-radix-collection-item]',
|
|
'[data-radix-dropdown-menu-trigger]',
|
|
'[data-radix-dropdown-menu-content]',
|
|
'[data-radix-dropdown-menu-item]',
|
|
'[data-state]', // Radix UI elements often have data-state
|
|
'.dropdown-menu',
|
|
'.dropdown-trigger',
|
|
'input',
|
|
'select',
|
|
'textarea',
|
|
'a[href]',
|
|
'[tabindex]:not([tabindex="-1"])',
|
|
'[onclick]',
|
|
'svg', // Icons within buttons
|
|
'.lucide' // Lucide icons specifically
|
|
].join(', '))
|
|
```
|
|
|
|
### 2. Parent Element Traversal
|
|
|
|
Added logic to traverse up the DOM tree to check for elements with event handlers:
|
|
|
|
```typescript
|
|
let currentElement: HTMLElement | null = target
|
|
while (currentElement && currentElement !== event.currentTarget) {
|
|
if (
|
|
currentElement.onclick ||
|
|
currentElement.getAttribute('role') === 'button' ||
|
|
currentElement.tagName === 'BUTTON' ||
|
|
(currentElement.classList.contains('cursor-pointer') &&
|
|
currentElement !== event.currentTarget)
|
|
) {
|
|
return // Don't emit row-click
|
|
}
|
|
currentElement = currentElement.parentElement
|
|
}
|
|
```
|
|
|
|
### 3. Enhanced Event Prevention in Columns
|
|
|
|
The `columns.ts` file was already enhanced by the IDE autofix to include `onMouseDown` event handlers on all dropdown elements:
|
|
|
|
```typescript
|
|
// Dropdown trigger
|
|
h(DropdownMenuTrigger, {
|
|
asChild: true,
|
|
onMouseDown: (e: Event) => {
|
|
e.stopPropagation()
|
|
},
|
|
onClick: (e: Event) => {
|
|
e.stopPropagation()
|
|
e.preventDefault()
|
|
}
|
|
})
|
|
|
|
// Dropdown content and items
|
|
h(DropdownMenuContent, {
|
|
align: 'end',
|
|
onMouseDown: (e: Event) => {
|
|
e.stopPropagation()
|
|
},
|
|
onClick: (e: Event) => {
|
|
e.stopPropagation()
|
|
}
|
|
})
|
|
```
|
|
|
|
## Files Modified
|
|
|
|
### 1. `frontend/src/components/shot/ShotsDataTable.vue`
|
|
- Enhanced `handleRowClick` function with comprehensive interactive element detection
|
|
- Added parent element traversal logic
|
|
- Fixed TypeScript typing for element traversal
|
|
- Removed unused `computed` import
|
|
|
|
### 2. `frontend/src/components/shot/columns.ts` (Enhanced by IDE autofix)
|
|
- Added `onMouseDown` event handlers to all dropdown elements
|
|
- Enhanced event prevention with both `stopPropagation()` and `preventDefault()`
|
|
- Improved event handling for all dropdown menu items
|
|
|
|
## Testing
|
|
|
|
### Test File Created
|
|
- `frontend/test-shot-delete-event-bubbling-final-fix.html` - Comprehensive test interface
|
|
|
|
### Test Scenarios Covered
|
|
1. **Row Click Test**: Clicking on non-interactive areas should trigger row click
|
|
2. **Dropdown Button Test**: Clicking the three-dot menu button should NOT trigger row click
|
|
3. **Menu Item Test**: Clicking "Edit Shot" or "View Tasks" should NOT trigger row click
|
|
4. **Delete Test**: Clicking "Delete Shot" should NOT trigger row click (main issue)
|
|
5. **Icon Test**: Clicking directly on SVG icons within buttons should NOT trigger row click
|
|
|
|
### Expected Results
|
|
- ✅ Row clicks work on non-interactive areas
|
|
- ✅ Dropdown button clicks don't trigger row click
|
|
- ✅ Menu item clicks don't trigger row click
|
|
- ✅ Delete button clicks don't trigger row click
|
|
- ✅ Shot detail panel doesn't open during delete operations
|
|
|
|
## Technical Details
|
|
|
|
### Event Flow
|
|
1. User clicks delete button in dropdown menu
|
|
2. `onMouseDown` handler on dropdown elements prevents initial bubbling
|
|
3. `onClick` handler on menu item executes delete action
|
|
4. Enhanced `handleRowClick` function detects interactive element and prevents row click emission
|
|
5. Shot detail panel remains closed during delete operation
|
|
|
|
### Browser Compatibility
|
|
- Uses standard DOM traversal methods (`closest`, `parentElement`)
|
|
- Compatible with all modern browsers
|
|
- Handles both mouse and touch events
|
|
|
|
### Performance Impact
|
|
- Minimal performance impact due to efficient DOM traversal
|
|
- Event prevention happens early in the event chain
|
|
- No unnecessary event listeners or watchers added
|
|
|
|
## Prevention Measures
|
|
|
|
To prevent similar issues in the future:
|
|
|
|
1. **Comprehensive Testing**: Always test interactive elements within table rows
|
|
2. **Event Handler Documentation**: Document all event prevention strategies
|
|
3. **Radix UI Awareness**: Be aware of Radix UI's dynamic attributes and event handling
|
|
4. **Icon Handling**: Remember that SVG icons can be click targets within buttons
|
|
5. **Parent Traversal**: Consider parent element event handlers when preventing bubbling
|
|
|
|
## Verification
|
|
|
|
The fix can be verified by:
|
|
1. Opening the shot table in the application
|
|
2. Clicking the three-dot menu on any shot row
|
|
3. Clicking "Delete Shot" option
|
|
4. Confirming that the shot detail panel does NOT open
|
|
5. Confirming that the delete confirmation dialog opens instead
|
|
|
|
## Related Issues
|
|
|
|
This fix resolves the core issue where delete actions were inadvertently opening the shot detail panel, improving the user experience and preventing confusion during delete operations. |