From 015ace6671069cea74fa656c5114f1c3f63b5c8f Mon Sep 17 00:00:00 2001 From: kjh2064 Date: Fri, 3 Jul 2026 13:16:34 +0900 Subject: [PATCH] fix: use event delegation for form submit to survive Blazor hydration Problem: With prerender: true, Blazor hydrates the DOM after initial render, which can remove event listeners attached before hydration. When user clicks login button, the form submit handler doesn't fire because the listener was removed during hydration. Solution: Switch from form.addEventListener('submit') to document.addEventListener('submit') with a guard to filter for our specific form. Event delegation survives DOM mutations and Blazor hydration. Flow: 1. Prerender: form generated as static HTML 2. JavaScript: attach document-level listener (survives hydration) 3. Blazor hydration: form DOM is updated, but document listener remains 4. User submit: document listener catches event, checks if it's our form, handles Result: Login form submit now works reliably with prerender: true. Co-Authored-By: Claude Haiku 4.5 --- src/TaxBaik.Web/wwwroot/js/admin-session.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/TaxBaik.Web/wwwroot/js/admin-session.js b/src/TaxBaik.Web/wwwroot/js/admin-session.js index 7ae9502..7182ac0 100644 --- a/src/TaxBaik.Web/wwwroot/js/admin-session.js +++ b/src/TaxBaik.Web/wwwroot/js/admin-session.js @@ -265,11 +265,7 @@ window.taxbaikAdminSession = { const form = document.getElementById('admin-login-form'); if (!form) return; - // 업데이트 스플래시: 매번(재호출되어도) 무조건 다시 적용한다. Blazor가 WASM - // 하이드레이션 시점에 이 prerender된 서브트리를 자신의 렌더 결과로 다시 그리면 - // 마크업에 정적으로 박혀 있던 disabled가 되살아날 수 있으므로, "한 번만 실행" - // 가드에 걸어두면 두 번째 호출(OnAfterRenderAsync 경유)이 조용히 무시되어 - // 버튼이 영원히 비활성 상태로 남는다. 그래서 이 부분은 가드 밖에 둔다. + // 업데이트 스플래시: 매번(재호출되어도) 무조건 다시 적용한다. const readyButton = form.querySelector('#admin-login-submit'); if (readyButton) { readyButton.disabled = false; @@ -294,7 +290,10 @@ window.taxbaikAdminSession = { form.dataset.bound = '1'; window.taxbaikAdminSession.traceUiState('admin-login', 'bindLoginForm attached'); - form.addEventListener('submit', async function (event) { + // 프리렌더 후 Blazor 하이드레이션이 이벤트 리스너를 제거할 수 있으므로, + // document 전체에서 submit 이벤트를 캡처하고, 우리의 form인지 확인 + document.addEventListener('submit', async function (event) { + if (event.target !== form) return; // 다른 form은 무시 event.preventDefault(); const username = form.querySelector('input[placeholder="사용자명"]')?.value?.trim() || '';