เบราว์เซอร์มีการโต้ตอบและพฤติกรรม Default สำหรับ Event ต่างๆ
ตัวอย่าง: User กดปุ่ม "Submit" บน Form -> Form ส่งข้อมูลไป URL โดย Default
คลิก Child Element -> Click Event เกิดบน Parent ด้วย (เพราะ Child อยู่ใน Container)
บางกรณีอยาก Override Default นี้ บทความนี้สอน event.preventDefault() และ event.stopPropagation() ยกเลิก Default Actions ในเบราว์เซอร์
event.preventDefault()
ป้องกัน Default Actions ที่เบราว์เซอร์ทำเมื่อ Event ถูก Trigger
Override Default Form Submission
Submit Form (กดปุ่ม Submit) -> Default: ส่ง Form Data ไป URL ตาม action และ method (get, post) หากไม่ระบุ: URL = Current Page, Method = GET
โค้ด HTML:
<form>
<input name="email" />
<input name="password" />
<input type="submit" />
</form>
Submit ด้วย "dillion" และ "password" -> GET Request ไป 127.0.0.1:5500/index.html
แต่มันมักต้อง: Validate, Check, Process, Config Headers ก่อนส่ง Request
วิธีป้องกัน Default:
<form id='form'> ... </form>
const form = document.getElementById('form')
form.addEventListener('submit', (event) => {
event.preventDefault()
// process data และส่ง request เอง
})
ตอนนี้การ Submit Form อยู่ในมือคุณ
Override Default Link Click
คลิก Link (<a href>) -> Default: Navigate ไป URL นั้น
อยาก Intercept ทำอะไรก่อน Navigate?เช่น Check Permission
<a id="link" href="https://google.com">Google</a>
const link = document.getElementById("link")
link.addEventListener("click", event => {
event.preventDefault()
// do something แล้ว navigate เอง
})
ทดสอบ: คลิก "Google" -> ไม่ Navigate เพราะ Prevent Default แล้ว ต้อง Handle Navigation เอง
event.stopPropagation()
Propagation = การแพร่กระจาย Event stopPropagation หยุดการแพร่กระจายเมื่อ Event Trigger บน Element
ใน JS: Trigger Event บน Element -> Event Bubble ขึ้นไป Parents/Ancestors (Child อยู่ใน Container -> Parent รับ Event)
คลิก Child ของ Element
HTML:
<div>
<button>Click me</button>
</div>
คลิก Button -> คลิก Div ด้วย (Button ใน Container) Event Propagate Button -> Div -> Grandparents -> Root
ทดสอบโค้ด:
<div id="div">
<button id="button">Click me</button>
</div>
const div = document.getElementById('div')
const button = document.getElementById('button')
button.addEventListener('click', () => console.log('button clicked'))
div.addEventListener('click', () => console.log('div container clicked'))
คลิก Button -> Console แสดงทั้ง 2 บรรทัด (Div ก็รับ Event)
ตัวอย่างจริง: Gmail New Message Popup
Top Bar: 3 ปุ่ม (Minimize, Fullscreen, Close) + ข้อความ "New Message" มี Click Handler -> Minimize Popup
ปัญหา: กดปุ่ม Close -> Event Propagate ไป Top Bar -> Minimize ด้วย (ไม่ต้องการ!)
แก้ด้วย stopPropagation() บนปุ่ม:
<div id='top-bar'>
<!-- Message -->
<!-- Buttons -->
</div>
const topBar = document.getElementById('top-bar')
const closeButton = document.getElementById('close-btn')
topBar.addEventListener('click', () => { /* minimize/maximize */ })
closeButton.addEventListener('click', (event) => {
event.stopPropagation()
// close popup
})
ตอนนี้ Top Bar รับ Event เฉพาะคลิกโดยตรงเท่านั้น
สรุป
ความแตกต่าง:
event.preventDefault()- ป้องกัน Default Action ของ **Browser** (Submit Form, Navigate Link)event.stopPropagation()- ป้องกัน Default Behavior ของ **Event** (Bubbling ขึ้น Tree)
Default Actions/Behaviors ไม่ใช่ Bug ไม่ต้องกังวลตอนเขียนโค้ด แต่บาง Scenario ต้อง Override ตามตัวอย่างข้างต้น