Lampirkan acara ke elemen dinamis dalam javascript

90

Saya mencoba memasukkan data html secara dinamis ke daftar yang dibuat secara dinamis, tetapi ketika saya mencoba untuk melampirkan acara onclick untuk tombol yang dibuat secara dinamis, acara tersebut tidak diaktifkan. Solusi akan sangat dihargai.

Kode Javascript:

document.addEventListener('DOMContentLoaded', function () {
document.getElementById('btnSubmit').addEventListener('click', function () {
    var name = document.getElementById('txtName').value;
    var mobile = document.getElementById('txtMobile').value;
    var html = '<ul>';
    for (i = 0; i < 5; i++) {
        html = html + '<li>' + name + i + '</li>';
    }
    html = html + '</ul>';

    html = html + '<input type="button" value="prepend" id="btnPrepend" />';
    document.getElementsByTagName('form')[0].insertAdjacentHTML('afterend', html);
});

document.getElementById('btnPrepend').addEventListener('click', function () {
    var html = '<li>Prepending data</li>';
    document.getElementsByTagName('ul')[0].insertAdjacentHTML('afterbegin', html);
});

});

Kode HTML:

<form>
    <div class="control">
        <label>Name</label>
        <input id="txtName" name="txtName" type="text" />
    </div>
    <div class="control">
        <label>Mobile</label>
        <input id="txtMobile" type="text" />
    </div>
    <div class="control">
        <input id="btnSubmit" type="button" value="submit" />
    </div>
</form>
Manju
sumber
Bagaimana Anda membuat html?
jim0thy
1
Saya akan mengatakan itu karena elemen tidak ada ketika Anda mencoba melampirkan pendengar acara. - lihat learn.jquery.com/events/event-delegation
Craicerjack
1
Pindahkan addEventListener Anda ke pendengar acara btnSubmit
slebetman

Jawaban:

199

Ini karena fakta bahwa elemen Anda dibuat secara dinamis. Anda harus menggunakan delegasi acara untuk menangani acara tersebut.

 document.addEventListener('click',function(e){
    if(e.target && e.target.id== 'brnPrepend'){
          //do something
     }
 });

jquery membuatnya lebih mudah:

 $(document).on('click','#btnPrepend',function(){//do something})

Berikut adalah artikel tentang artikel acara delegasi acara delegasi

jilykate
sumber
1
Terima kasih! Terkadang solusi JS murni tidak berfungsi di iphone, tetapi jika mengubah dokumen di div induk lain, misalnya, ini berfungsi. Apa solusi terbaik untuk pendelegasian?
Kholiavko
3
@Kholiavko Saya akan mengatakan selama elemen "induk" tidak dibuat secara dinamis, itu harus bekerja. Saya akan mengikat event handler ke induk pertama dari elemen dynamic create d sehingga tidak ada konflik antara event handler yang berbeda
jilykate
1
Tapi terkadang itu tidak berfungsi di iphone, bahkan elemen "induk" tidak dibuat secara dinamis. Ini adalah contoh , ini berfungsi di semua browser, tetapi tidak di iphone (safary dan bahkan chrome). Dan saya tidak mengerti mengapa.
Kholiavko
2
@Kholiavko ini hanya karena codepen menggunakan kotak pasir untuk membungkus semuanya. Jika Anda benar-benar menulis kode tersebut di halaman biasa, kode itu akan berfungsi
jilykate
2
Pertimbangkan untuk menambahkan tanda sama dengan ekstra (===) untuk mencegah pemaksaan tipe yang tidak terduga
Staccato
17

Ada solusi dengan menangkap klik document.bodydan kemudian memeriksa target acara.

document.body.addEventListener( 'click', function ( event ) {
  if( event.srcElement.id == 'btnSubmit' ) {
    someFunc();
  };
} );
Manasov Daniel
sumber
2
Atau kontainer terdekat
mplungjan
Jawaban yang tepat!
Rahul Purohit
WOW ini luar biasa, menghemat banyak waktu dan kode! :)
Anna Medyukh
Catatan: event.srcElement tidak digunakan lagi. Sebaiknya gunakan event.target sebagai gantinya.
dsanchez
12

Anda harus melampirkan acara setelah menyisipkan elemen, seperti itu Anda tidak melampirkan acara global pada Anda documenttetapi acara tertentu pada elemen yang disisipkan.

misalnya

document.getElementById('form').addEventListener('submit', function(e) {
  e.preventDefault();
  var name = document.getElementById('txtName').value;
  var idElement = 'btnPrepend';
  var html = `
    <ul>
      <li>${name}</li>
    </ul>
    <input type="button" value="prepend" id="${idElement}" />
  `;
  /* Insert the html into your DOM */
  insertHTML('form', html);
  /* Add an event listener after insert html */
  addEvent(idElement);
});

const insertHTML = (tag = 'form', html, position = 'afterend', index = 0) => {
  document.getElementsByTagName(tag)[index].insertAdjacentHTML(position, html);
}
const addEvent = (id, event = 'click') => {
  document.getElementById(id).addEventListener(event, function() {
    insertHTML('ul', '<li>Prepending data</li>', 'afterbegin')
  });
}
<form id="form">
  <div>
    <label for="txtName">Name</label>
    <input id="txtName" name="txtName" type="text" />
  </div>
  <input type="submit" value="submit" />
</form>

R3tep
sumber
2
Pendekatan ini hanya akan bekerja untuk CSR (Client Side Rendering). Ini tidak akan berfungsi untuk SSR (Server-Side Rendering). Untuk membuatnya berfungsi baik untuk CSR dan SSR, Event Delegation adalah solusinya:javascript document.addEventListener('click',function(e){ if(e.target && e.target.id== 'brnPrepend'){ //do something } });
Yatendra Goel
Tetapi untuk alasan kinerja, pendekatan ini lebih baik. Jadi itu tergantung kasus penggunaan Anda.
R3tep
8

Perbedaannya terletak pada cara Anda membuat dan menambahkan elemen di DOM.

Jika Anda membuat elemen melalui document.createElement, tambahkan event listener, dan tambahkan ke DOM. Acara Anda akan aktif.

Jika Anda membuat elemen sebagai string seperti ini: html + = "<li> test </li>" `, elemen secara teknis hanyalah string. String tidak boleh memiliki pemroses acara.

Salah satu solusinya adalah membuat setiap elemen dengan document.createElementdan kemudian menambahkannya ke elemen DOM secara langsung.

// Sample
let li = document.createElement('li')
document.querySelector('ul').appendChild(li)
Richard
sumber
3

Anda dapat melakukan sesuatu yang mirip dengan ini:

// Get the parent to attatch the element into
var parent = document.getElementsByTagName("ul")[0];

// Create element with random id
var element = document.createElement("li");
element.id = "li-"+Math.floor(Math.random()*9999);

// Add event listener
element.addEventListener("click", EVENT_FN);

// Add to parent
parent.appendChild(element);
PRDeving
sumber
2
var __ = function(){
    this.context  = [];
    var self = this;
    this.selector = function( _elem, _sel ){
        return _elem.querySelectorAll( _sel );
    }
          this.on = function( _event, _element, _function ){
              this.context = self.selector( document, _element );
              document.addEventListener( _event, function(e){
                  var elem = e.target;
                  while ( elem != null ) {
                      if( "#"+elem.id == _element || self.isClass( elem, _element ) || self.elemEqal( elem ) ){
                          _function( e, elem );
                      }
                      elem = elem.parentElement;
                  }
              }, false );
     };

     this.isClass = function( _elem, _class ){
        var names = _elem.className.trim().split(" ");
        for( this.it = 0; this.it < names.length; this.it++ ){
            names[this.it] = "."+names[this.it];
        }
        return names.indexOf( _class ) != -1 ? true : false;
    };

    this.elemEqal = function( _elem ){
        var flg = false;
        for( this.it = 0; this.it < this.context.length;  this.it++ ){
            if( this.context[this.it] === _elem && !flg ){
                flg = true;
            }
        }
        return flg;
    };

}

    function _( _sel_string ){
        var new_selc = new __( _sel_string );
        return new_selc;
    }

Sekarang Anda dapat mendaftarkan acara seperti,

_( document ).on( "click", "#brnPrepend", function( _event, _element ){
      console.log( _event );
      console.log( _element );
      // Todo

  });

Dukungan Browser

chrome - 4.0, Edge - 9.0, Firefox - 3.5 Safari - 3.2, Opera - 10.0 dan yang lebih baru

paranjothi
sumber
2

Saya telah membuat perpustakaan kecil untuk membantu ini: Sumber perpustakaan di GitHub

<script src="dynamicListener.min.js"></script>
<script>
// Any `li` or element with class `.myClass` will trigger the callback, 
// even elements created dynamically after the event listener was created.
addDynamicEventListener(document.body, 'click', '.myClass, li', function (e) {
    console.log('Clicked', e.target.innerText);
});
</script>

Fungsinya mirip dengan jQuery.on ().

Pustaka menggunakan metode Element.matches () untuk menguji elemen target terhadap selektor yang diberikan. Ketika sebuah peristiwa dipicu, callback hanya dipanggil jika elemen target cocok dengan selektor yang diberikan.

XCS
sumber
0

Saya tahu bahwa topiknya terlalu lama tetapi saya memberi diri saya beberapa menit untuk membuat kode yang sangat berguna yang berfungsi dengan baik dan sangat mudah menggunakan pure JAVASCRIPT. Berikut kode dengan contoh sederhana:

String.prototype.addEventListener=function(eventHandler, functionToDo){
  let selector=this;
  document.body.addEventListener(eventHandler, function(e){
    e=(e||window.event);
    e.preventDefault();
    const path=e.path;
    path.forEach(function(elem){
      const selectorsArray=document.querySelectorAll(selector);
      selectorsArray.forEach(function(slt){
        if(slt==elem){
          if(typeof functionToDo=="function") functionToDo(el=slt, e=e);
        }
      });
    });
  });
}

// And here is how we can use it actually !

"input[type='number']".addEventListener("click", function(element, e){
	console.log( e ); // Console log the value of the current number input
});
<input type="number" value="25">
<br>
<input type="number" value="15">
<br><br>
<button onclick="addDynamicInput()">Add a Dynamic Input</button>
<script type="text/javascript">
  function addDynamicInput(){
    const inpt=document.createElement("input");
          inpt.type="number";
          inpt.value=Math.floor(Math.random()*30+1);
    document.body.prepend(inpt);
  }
</script>

Adnane Ar
sumber
0

Saya telah membuat fungsi sederhana untuk ini.

The _caseFungsi memungkinkan Anda untuk tidak hanya mendapatkan target, tetapi juga mendapatkan elemen induk di mana Anda mengikat acara pada.

Fungsi callback mengembalikan peristiwa yang menampung target ( evt.target) dan elemen induk yang cocok dengan selector ( this). Di sini Anda dapat melakukan hal-hal yang Anda butuhkan setelah elemen diklik.

Saya belum memutuskan mana yang lebih baik, if-elseatau yangswitch

var _case = function(evt, selector, cb) {
  var _this = evt.target.closest(selector);
  if (_this && _this.nodeType) {
    cb.call(_this, evt);
    return true;
  } else { return false; }
}

document.getElementById('ifelse').addEventListener('click', function(evt) {
  if (_case(evt, '.parent1', function(evt) {
      console.log('1: ', this, evt.target);
    })) return false;

  if (_case(evt, '.parent2', function(evt) {
      console.log('2: ', this, evt.target);
    })) return false;

  console.log('ifelse: ', this);
})


document.getElementById('switch').addEventListener('click', function(evt) {
  switch (true) {
    case _case(evt, '.parent3', function(evt) {
      console.log('3: ', this, evt.target);
    }): break;
    case _case(evt, '.parent4', function(evt) {
      console.log('4: ', this, evt.target);
    }): break;
    default:
      console.log('switch: ', this);
      break;
  }
})
#ifelse {
  background: red;
  height: 100px;
}
#switch {
  background: yellow;
  height: 100px;
}
<div id="ifelse">
  <div class="parent1">
    <div class="child1">Click me 1!</div>
  </div>
  <div class="parent2">
    <div class="child2">Click me 2!</div>
  </div>
</div>

<div id="switch">
  <div class="parent3">
    <div class="child3">Click me 3!</div>
  </div>
  <div class="parent4">
    <div class="child4">Click me 4!</div>
  </div>
</div>

Semoga membantu!

ssten
sumber
0

Saya telah menemukan solusi yang diposting oleh jillykate bekerja, tetapi hanya jika elemen target adalah yang paling bersarang. Jika ini tidak terjadi, ini dapat diperbaiki dengan mengulangi orang tua, yaitu

function on_window_click(event)
{
    let e = event.target;

    while (e !== null)
    {
        // --- Handle clicks here, e.g. ---
        if (e.getAttribute(`data-say_hello`))
        {
            console.log("Hello, world!");
        }

        e = e.parentElement;
    }
}

window.addEventListener("click", on_window_click);

Perhatikan juga bahwa kami dapat menangani acara dengan atribut apa pun, atau melampirkan pendengar kami di tingkat mana pun. Kode di atas menggunakan atribut khusus dan window. Saya ragu ada perbedaan pragmatis antara berbagai metode.

cz
sumber