การ bind event ให้กับ element ที่ยังไม่เกิด

การทำงานกับ Ajax เราจำเป็นต้องมีการ bind event ให้กับ element ที่ยังไม่เกิด ยกตัวอย่างเช่นถ้าเราต้องการ bind event ให้กับปุ่ม delete ที่อยู่ในแต่ละแถวของตารางที่ทำการ Ajax Call ไปดึงข้อมูลมาจากฝั่ง Server(ในตอน document ready จะยังไม่มีข้อมูลซักแถว) ก็ในเมื่อการ bind event onclick จำเป็นต้องทำการเขียน selector เพื่อให้ได่้ element นั้นมาก่อนแล้วค่อยใช้ .on หรือ .click bind event ให้กับ element นั้นๆ

วิธีการแก้ปัญหาอย่างแรกก็คือ ย้ายการ bind event ให้ไปทำงานตอน call back function ซึ่งจะทำงานได้เหมือนกันแต่จะทำให้ code ดูยุ่งยากและซับซ้อน ในบทความนี้เราเลยหยิบเอาประเด็นเรื่องนี้มาแก้ปัญหากัน โดยใช้วิธี bind event ให้กับ element ก่อนที่ element นั้นจะเกิดขึ่นจริงๆ

เริ่มจากเราจะสมมุติว่าให้ append element เข้าไปหลังจากผ่านไป 5 วินาที(เหมือนกับเราทำ Ajax call ไปยัง Server) โดยใช้ Code ด้านล่างนี้

และ target ที่เราจะ append element เข้าไปสมมุติให้เป็น div ที่ตั้ง id เป็น target แบบนี้

ขั้นตอนแรกเราจะทำการ select element ที่เป็น parent ของ target ที่เราต้องการ เช่นจากตัวอย่างเราก็ทำการ query เอา div ที่เป็น target(แทนที่จะ query เอาปุ่มที่อยู่ใน div นั้นมา bind event)

หลังจาก query target มาได้แล้วก็ให้ใช้ .on เหมือนปกติแต่เพิ่ม parameter ตัวที่ 2 ขึ้นมา ซึ่ง parameter ตัวนี้จะเป็น selector ไป query element ลูกอีกทีนึง(ซึ่งก็คือ element ที่ยังไม่เกิดนั่นเอง) จากในตัวอย่างเราจะทำการ query button ทุกตัวที่อยู่ใน div(ซึ่ง button จะยังไม่ในตอนเริ่มต้น แต่จะค่อยๆเพิ่มขึ้นทุกๆ 5 วินาที) แล้ว bind event onclick นี้ให้กับทุกๆ button ทั้งที่เกิดขึ้นมาแล้วและกำลังจะเกิดขึ่นในอนาคต

การ propagation ของ javascript

propagation ตามความหมายในพจนานุกรมหมายถึงการแพร่พันธ์ ดังนั้นใน javascript ก็จะใช้ในลักษณะที่ใกล้เคียงกัน ดังในตัวอย่างนี้

เริ่มต้นจากการที่มี

ในตัวอย่งจะมี span วางอยู่บน p และ ทั้งสอง element นี้ก็วางอยู่บน div อีกทีนึง ดังนั้นการ propagation ก็จะเกิดขึ้น เมื่อไหร่ที่มีการ click ที่ element span ก็จะเกิดการแพร่พันธ์ของการ click ไปยัง p และ div ด้วย หมายถึงเรา click แค่ span แต่เหมือนเราได้ click ทั้ง span, p และ div พร้อมๆกัน ดังนั้นถ้าเราไม่ให้เกิดการ propagate ก็ให้ทำการใช้ คำสั่ง event.stopPropagation() ซึ่งจะต้องรับ event object เข้ามาก่อน ซึ่งในทุกๆ event จะมี event object ให้ใช้งานอยู่แล้ว ยกตัวอย่างเช่น

จากในตัวอย่างเรารับ parameter ของ function มาเป็น event เราก็เลยสั่งให้หยุดการ propagate ด้วย event.stopPpropagation(); ทำให้การ click ที่ span จะไม่ไปเรียก onclick ของ p และ div ขึ้นมาทำงาน ตรงกันข้ามถ้าเรา comment เอา event.stopPropagation() ออก ก็จะพบว่าเมื่อเรา click ที่ span จะมี pop up ขึ้นมา 3 ครั้ง เนื่องจาก event onclick ของ span, p และ div ถูกเรียกขึ้นมาใช้งานตามลำดับ

การใช้งาน closest() ใน jquery

การทำงานของ closest() จะเหมือนกับการทำงานของ function parents (ไม่ใช่ parent เฉยๆนะ เพราะจะหาแค่ ชั้นบนที่ติดตัวชั้นเดียวเท่านั้น เพราะ parent จริงๆแล้วหมายถึงพ่อแม่ ไม่รวมปู่กับย่า) แต่จะต่างกันตรงที่ถ้าใช้ parents() จะหาเฉพาะ ชั้นที่เป็นแม่ของมันเท่านั้น แต่จะไม่ได้สนใจว่า element ปัจจุบันนั้นเป็นอะไร แต่ถ้าเป็น closest() จะทำการเปรียบเทียบตัวมันเองก่อนแล้วถึงจะมองขึ้นไปยังแม่ของ element นั้นๆอีกที โดยที่ function closest() นั้นจะทำการ return element ที่มันต้องการเพียงแค่ element เดียวเท่านั้น

ตัวอย่าง

ถ้าเราอยากได้ parent ตัวแรกสุดที่เป็น ul ของ span ให้เขียนแบบนี้

การทำงานจะเริ่มจากการหา span แลัวไล่จาก span ขึ้นไปเรื่อยๆ จนกระทั่งเจอ ul แล้วก็หยุดทำงาน แต่ถ้า element ที่เราทำการเลือกใน selector เป็น ul อยู่แล้วก็จะไม่ได้ทำการค้นหาอะไรแล้วก็ return element ปัจจุบันออกไป

แล้วกรณีไหนที่ต้องการใช้งาน closest() เพราะปกติเราจะใช้ parents กันอยู่แล้ว คำตอบคือใช้ในกรณีที่ต้องการหาตัวแม่เพียงตัวเดียวเท่านั้น เพราะเมื่อเจอแล้วก็จะหยุดค้นหา แต่ถ้าเราเปลี่ยน code ใหม่เป็น parents แบบนี้

ผลลัพธ์ที่ได้คือ ul ทั้ง 2 level จะมีกรอบสีแดงทั้ง 2 element

การใช้ jquery แทน media query

การใช้งาน Media Query ยังมีข้อจำกัดอยู่ที่่ต้องการ Browser รุ่นใหม่ๆ
ซึ่งจะมี IE ที่ยังไม่ Support และยังมีผู้ใช้งานอยู่มาก
แต่เราสามารถที่จะใช้ jQuery มาใช้ในการจัดการแทน Media query ได้โดยเราสามารถหาความกว้างของ window ได้โดยใช้

1
$(window).width()

นอกจากนั้นเรายังดักจับ event resize window ได้ด้วย $(window).resize(); เราสามารถจะเขียน Code ได้แบบนี้

1
2
3
4
5
6
7
8
9
10
$(window).resize(function(){
     var width = $(window).width();
     if(width > 760){
         $('h1').attr('class','web');
     }else if(width > 480 ){
         $('h1').attr('class','tablet');
     }else if(width > 0){
         $('h1').attr('class','mobile');
     }
});

ที่ใช้ .attr แทน addClass เพราะจะได้ replace Class ทั้งหมด แต่ถ้าเราต้องการ เพิ่ม Class เข้าไปซึ่งส่วนใหญ่ในงานจริงเป็นแบบนั้น เราจะใช้ addClass แทน อันนี้จะขึ้นอยู่กับรูปแบบการเขียน Stylesheet ของเรา