Memahami Event Bubbling dan Method .on() di jQuery


Pada jlSimpleTableEditor (yang ada di artikel Menghasilkan Tabel Editor Sederhana Dengan Widget jQuery), setiap kali sebuah baris ditambahkan, maka method _buatTombolEdit() dan _buatTombolHapus akan dipanggil.  Didalam kedua method tersebut, akan dibuat event handler baru untuk kedua tombol tersebut.  Hal ini berarti bila ada 10 baris, maka akan terdapat 20 event handler (untuk 2 tombol di setiap baris).  Bagaimana bila ada 100 baris?  Akan ada 200 event handler!  Walaupun overhead ini mungkin tidak akan terasa pada pengguna yang memiliki PC canggih, tapi saya bisa melakukan optimalisasi disini.

Di JavaScript, sebuah event untuk sebuah elemen, akan disampaikan juga kepada elemen yang mengandungnya atau element parent.  Lalu dari parent ke parent-nya parent.  Begitu seterusnya, hingga akhirnya sampai ke yang paling atas, yaitu document.  Perilaku ini biasanya disebut sebagai event bubbling atau event propagation.

Mari lakukan pembuktian sederhana mengenai event bubbling.  Saya membuat sebuah HTML seperti berikut ini:

<html>
  <head>
  </head>
  <body>
    <div id="div1">
      <div id="div2">
        <p id="paragraph">
          <input type="button" value="Klik Disini" id="tombol" />
        </p>
      </div>
    </div>
    <script>
      function pesan(e) {
        alert('Event target adalah ' + e.target.id);
      }
      document.getElementById("tombol").onclick = pesan;
      document.getElementById("paragraph").onclick = pesan;
      document.getElementById("div2").onclick = pesan;
      document.getElementById("div1").onclick = pesan;
    </script>
  </body> 
</html>

Jika tombol di-klik, maka akan muncul kotak dialog 4 kali!  Yup, 4 kali, tetapi isinya selalu sama, yaitu “Event target adalah tombol”.  Padahal, ada 4 elemen yang berbeda yang berusaha menangani click event.  Ini yang disebut event bubblingclick event yang terjadi pada elemen dengan id tombol telah menggelembung naik ke element dengan id paragraph, lalu naik lagi ke div2, lalu naik lagi ke div1, kemudian ke document (akan diabaikan karena tidak handler onclick disini).

Untuk memperjelas konsep event bubbling, sekarang saya mengubah function pesan() di atas menjadi seperti berikut ini:

function pesan(e) {
  alert("Event target adalah " + e.target.id);
  e.stopPropagation(); // menghentikan event bubbling!
}

Sekarang, bila saya men-klik tombol, maka kotak dialog yang muncul hanya 1 saja. Ini karena saya telah menghentikan event bubbling dengan memanggil method stopPropagation() milik Event Javascript.

Lalu bagaimana cara memanfaatkan event bubbling bagi jlSimpleTableEditor dalam mengurangi overhead?  Bila saya meletakkan event handler di <tbody>, bukan di masing-masing <tr>, maka hanya 2 event handler yang dibutuhkan, tidak peduli sebanyak apapun jumlah baris di tabel.  Hal ini karena setiap kali tombol Edit dan tombol Hapus (baik yang sudah ada maupun yang akan ditambahkan secara dinamis nanti) di-klik, maka event click tersebut akan di-propagate ke <tbody>.

Saya akan meletakkan event handler untuk tombol Edit dan tombol Hapus di method _create(). Karena method ini hanya akan dikerjakan pada saat widget dibuat, maka 2 event handler ini akan berlaku untuk seluruh baris yang sudah ada maupun yang akan ditambahkan secara dinamis nanti.  Isi kode program akan terlihat seperti:

_create: function() {

  // men-handle operasi "edit"
  $("tbody", this.element).on("click", "tr td input.jlEdit", $.proxy(function(e) {

    var indexBaris = jQuery.data(e.target, "baris");
    ... // isi event handler yang lama disini

  }, this));

  // men-handle operasi "Hapus"
  $("tbody", this.element).on("click", "tr td input.jlHapus",  $.proxy(function(e) {

    var indexBaris = jQuery.data(e.target, "baris");
    ... // isi event handler yang lama disini

  }, this));

  .. // kode program lainnya diabaikan
}

Pada kode program di atas, event handler diletakkan pada element <tbody>.  Bila ada event “click” yang di-propagate (bubble) dari "tr td input.jlEdit" ataupun "tr td input.jlHapus", maka kode event handler tersebut akan dikerjakan.   Yang menarik adalah nilai e.target tetap akan merujuk ke pemicu event, yaitu <input type='button'>.  Yup, karena target-nya memang bukan <tbody> walaupun saat ini sedang berada di <tbody>.  Dengan demikian, saya masih bisa tetap mendapatkan index baris mana yang akan di-proses melalui nilai e.target tersebut.

Method _buatTombolEdit() dan _buatTombolHapus() kini cukup hanya memanipulasi elemen tanpa ada kode program event handler.   Dengan demikian, isi kedua method tersebut cukup hanya:

_buatTombolEdit: function(indexBaris, parent) {
  $("<input />", {
    type: 'button',
    value: 'Edit',
    class: 'jlEdit'
  }).data('baris', indexBaris).appendTo(parent).wrap("<td />");
}

_buatTombolHapus: function(indexBaris, parent) {
  $("<input />", {
    type: 'button',
    value: 'Hapus',
    class: 'jlHapus'
  }).data('baris', indexBaris).appendTo(parent).wrap("<td />");
}

Perihal Solid Snake
I'm nothing...

Apa komentar Anda?

Please log in using one of these methods to post your comment:

Logo WordPress.com

You are commenting using your WordPress.com account. Logout / Ubah )

Gambar Twitter

You are commenting using your Twitter account. Logout / Ubah )

Foto Facebook

You are commenting using your Facebook account. Logout / Ubah )

Foto Google+

You are commenting using your Google+ account. Logout / Ubah )

Connecting to %s

%d blogger menyukai ini: