동적으로 생성 된 요소에 대한 jQuery "생성시"이벤트


81

동적으로 <select>요소를 생성 하고 jQuery로 전환 할 수 있어야합니다 .combobox(). 이것은 jQuery를 사용할 수있는 일부 "클릭"이벤트와는 반대로 요소 생성 이벤트 여야합니다 .on().

그렇다면 이와 같은 것이 존재합니까?

$(document).on("create", "select", function() {
    $(this).combobox();
}

나는 매우 구식이기 때문에 livequery를 사용하기를 꺼립니다.

업데이트 언급 한 select / combobox는 ajax를 통해 jQuery colorbox (모달 창)에로드되므로 문제는 colorbox를 사용하여 combobox 만 시작할 수 onComplete있지만 하나의 콤보 박스를 변경하면 다른 선택 / 콤보 박스를 동적으로 생성해야합니다. 요소 생성을 감지하는보다 일반적인 방법 ( select이 경우).

UPDATE2 문제를 더 시도하고 설명하기 위해- select/combobox재귀 적으로 생성 된 요소가 있고 내부에 많은 시작 코드가 .combobox()있으므로 @bipen의 답변 과 같은 고전적인 접근 방식을 사용하면 코드가 미친 수준으로 부 풀릴 것입니다. 이것이 문제를 더 잘 설명하기를 바랍니다.

UPDATE3 모두에게 감사합니다. 이제 사용 중단 이후 DOMNodeInsertedDOM 변이에 공백이 남아 있으며이 문제에 대한 해결책이 없다는 것을 이해합니다. 내 응용 프로그램을 다시 생각해야 할 것입니다.


1
준비된 이벤트와 함께 할 수 있습니까? $(select).ready(function() { });
Pablo Banderas 2013 년

@PabloBanderas ready는 "DOM이 완전히로드되었을 때 실행할 함수를 지정합니다."에 사용됩니다. (jquery.com에서)
Caballero

1
combobox()이후가 아닌 생성 / 삽입 시점에서 방법을 적용하지 않는 이유는 무엇 입니까?
다윗은 분석 재개 모니카 말한다

@DavidThomas 내 두 번째 업데이트에서 그 이유를 설명하기 위해 시도
Caballero에

그래서 $(document).on('onComplete', 'select', function(){ // bind here? });? (분명히보다 가까이 부모를 사용 document하지만,.)
다윗은 분석 재개 모니카 말한다

답변:


59

당신은 할 수 이벤트는이 코드가 문서에 추가되는 경우에 대한 이벤트를 얻을 수 있습니다.onDOMNodeInserted

$('body').on('DOMNodeInserted', 'select', function () {
      //$(this).combobox();
});

$('<select>').appendTo('body');
$('<select>').appendTo('body');

여기에 Fiddled : http://jsfiddle.net/Codesleuth/qLAB2/3/

편집 : 주변을 읽은 후 DOMNodeInserted브라우저에서 문제가 발생하지 않는지 다시 확인해야 합니다. 2010 년 의이 질문 은 IE가 이벤트를 지원하지 않는다는 것을 암시하므로 가능하면 테스트하십시오.

여기를보십시오 : [link] 경고! DOMNodeInserted 이벤트 유형은 참조 및 완전성을 위해이 사양에 정의되어 있지만이 사양 은이 이벤트 유형의 사용을 중단 합니다.


.delegatejQuery 버전 1.7에서 더 이상 사용되지 않고 .on?
Caballero 2013 년

1
네, 맞아요. 이 답변을 수정할 것이지만 DOMNodeInserted지금은 더 이상 사용되지 않기 때문에 이것을 사용 해야하는지 확실하지 않습니다.
Codesleuth 2013 년

on('DOMNodeInserted'이 질문을 게시하기 전에 시도했습니다 . 분명히 작동하지 않았습니다.
Caballero 2013 년

20
당신이 그것을 시도한 것은 당신의 질문이 아니기 때문에 나는 그것이 불공정 한 투표라고 말할 것입니다. 어쨌든 여기서 도와 드릴 수 없습니다.
Codesleuth 2013 년


20

다른 여러 답변에서 언급했듯이 돌연변이 이벤트 는 더 이상 사용되지 않으므로 MutationObserver 를 사용해야합니다. 대신 를 합니다. 아직 아무도 그것에 대해 자세히 설명하지 않았기 때문에 여기에 간다 ...

기본 JavaScript API

MutationObserver 용 API는 매우 간단합니다. 돌연변이 사건만큼 간단하지는 않지만 여전히 괜찮습니다.

function callback(records) {
  records.forEach(function (record) {
    var list = record.addedNodes;
    var i = list.length - 1;
    
	for ( ; i > -1; i-- ) {
	  if (list[i].nodeName === 'SELECT') {
	    // Insert code here...
	    console.log(list[i]);
	  }
	}
  });
}

var observer = new MutationObserver(callback);

var targetNode = document.body;

observer.observe(targetNode, { childList: true, subtree: true });
<script>
  // For testing
  setTimeout(function() {
    var $el = document.createElement('select');
    document.body.appendChild($el);
  }, 500);
</script>

그것을 분해합시다.

var observer = new MutationObserver(callback);

이것은 관찰자를 만듭니다. 관찰자는 아직 아무것도보고 있지 않습니다. 이것은 이벤트 리스너가 연결되는 곳입니다.

observer.observe(targetNode, { childList: true, subtree: true });

이렇게하면 관찰자가 시작됩니다. 첫 번째 인수는 관찰자가 변경 사항을 감시 할 노드입니다. 두 번째 인수는 감시 대상에 대한 옵션입니다 .

  • childList 추가되거나 제거되는 자식 요소를보고 싶다는 의미입니다.
  • subtree이 요소의 하위 트리 어디에서나 변경 사항을 감시 하도록 확장 되는 수정 자입니다 childList(그렇지 않으면에서 직접 변경 사항을 확인합니다 targetNode).

그 외의 다른 두 가지 주요 옵션 childListattributescharacterData입니다. 이 세 가지 중 하나를 사용해야합니다.

function callback(records) {
  records.forEach(function (record) {

콜백 내부에서 상황이 조금 까다로워집니다. 콜백은 MutationRecord 배열을 수신합니다 . 각 MutationRecord 한 유형의 몇 가지 변화를 설명 할 수 있습니다 ( childList, attributes또는 characterData). 관찰자에게를 보라고 만 말 childList했으므로 유형을 확인하지 않겠습니다.

var list = record.addedNodes;

여기에서 추가 된 모든 자식 노드의 NodeList를 가져옵니다. 노드가 추가되지 않은 모든 레코드에 대해 비어 있습니다 (이러한 레코드가 많을 수 있음).

거기에서 추가 된 노드를 반복하고 <select> 요소 인 .

여기에 정말 복잡한 것은 없습니다.

jQuery

...하지만 jQuery를 요청했습니다. 좋아.

(function($) {

  var observers = [];

  $.event.special.domNodeInserted = {

    setup: function setup(data, namespaces) {
      var observer = new MutationObserver(checkObservers);

      observers.push([this, observer, []]);
    },

    teardown: function teardown(namespaces) {
      var obs = getObserverData(this);

      obs[1].disconnect();

      observers = $.grep(observers, function(item) {
        return item !== obs;
      });
    },

    remove: function remove(handleObj) {
      var obs = getObserverData(this);

      obs[2] = obs[2].filter(function(event) {
        return event[0] !== handleObj.selector && event[1] !== handleObj.handler;
      });
    },

    add: function add(handleObj) {
      var obs = getObserverData(this);

      var opts = $.extend({}, {
        childList: true,
        subtree: true
      }, handleObj.data);

      obs[1].observe(this, opts);

      obs[2].push([handleObj.selector, handleObj.handler]);
    }
  };

  function getObserverData(element) {
    var $el = $(element);

    return $.grep(observers, function(item) {
      return $el.is(item[0]);
    })[0];
  }

  function checkObservers(records, observer) {
    var obs = $.grep(observers, function(item) {
      return item[1] === observer;
    })[0];

    var triggers = obs[2];

    var changes = [];

    records.forEach(function(record) {
      if (record.type === 'attributes') {
        if (changes.indexOf(record.target) === -1) {
          changes.push(record.target);
        }

        return;
      }

      $(record.addedNodes).toArray().forEach(function(el) {
        if (changes.indexOf(el) === -1) {
          changes.push(el);
        }
      })
    });

    triggers.forEach(function checkTrigger(item) {
      changes.forEach(function(el) {
        var $el = $(el);

        if ($el.is(item[0])) {
          $el.trigger('domNodeInserted');
        }
      });
    });
  }

})(jQuery);

이렇게하면 jQuery 특수 이벤트 API를domNodeInserted 사용하여 라는 새 이벤트가 생성 됩니다 . 다음과 같이 사용할 수 있습니다.

$(document).on("domNodeInserted", "select", function () {
  $(this).combobox();
});

일부 라이브러리는 select테스트 목적으로 요소를 생성하기 때문에 개인적으로 클래스를 찾는 것이 좋습니다 .

당연히 다음 .off("domNodeInserted", ...)과 같은 데이터를 전달하여 시청을 사용 하거나 미세 조정할 수도 있습니다 .

$(document.body).on("domNodeInserted", "select.test", {
  attributes: true,
  subtree: false
}, function () {
  $(this).combobox();
});

이렇게 select.test하면 본문 내부의 요소에 대한 속성이 변경 될 때마다 요소 의 모양을 확인합니다 .

아래 또는 jsFiddle 에서 라이브로 볼 수 있습니다 .


노트

이 jQuery 코드는 상당히 기본적인 구현입니다. 다른 곳에서 수정하여 선택기를 유효하게 만드는 경우에는 트리거되지 않습니다.

예를 들어 선택기가이고 .test select문서에 이미 <select>. 에 클래스 test를 추가하면 <body>선택기가 유효하지만 record.target및 만 확인하기 때문에 record.addedNodes이벤트가 발생하지 않습니다. 선택하려는 요소가 변경되어야합니다.

이것은 변이가 발생할 때마다 선택자를 쿼리하여 피할 수 있습니다. 이미 처리 된 요소에 대해 중복 이벤트가 발생하지 않도록하기 위해 그렇게하지 않기로 결정했습니다. 인접 하거나 일반적인 형제 결합 자를 올바르게 처리 하면 상황이 더욱 까다로워집니다.

보다 포괄적 인 솔루션 은 Damien Ó Ceallaigh답변 에서 언급했듯이 https://github.com/pie6k/jquery.initialize를 참조 하십시오 . 그러나 해당 라이브러리의 작성자는 라이브러리가 오래되었다고 발표했으며이를 위해 jQuery를 사용하지 말 것을 제안했습니다.


9

내 모든 아약스 문제를 해결할 수있는이 솔루션을 생각해 냈습니다.

준비된 이벤트의 경우 이제 다음을 사용합니다.

function loaded(selector, callback){
    //trigger after page load.
    $(function () {
        callback($(selector));
    });
    //trigger after page update eg ajax event or jquery insert.
    $(document).on('DOMNodeInserted', selector, function () {
        callback($(this));
    });
}

loaded('.foo', function(el){
    //some action
    el.css('background', 'black');
});

그리고 정상적인 트리거 이벤트의 경우 이제 다음을 사용합니다.

$(document).on('click', '.foo', function () {
    //some action
    $(this).css('background', 'pink');
});


4

DOM4 MutationObservers작업은 가능하지만 Firefox 14 + / Chrome 18+ (현재)에서만 작동합니다.

그러나 IE10, Firefox 5+, Chrome 3+, Opera 12, Android 2.0+, Safari 4+와 같은 CSS3 애니메이션을 지원하는 모든 브라우저에서 작동 하는 " 장대 한 해킹 "(저자의 말이 아닙니다!)이 있습니다. 블로그 에서 데모 를 참조하십시오 . 해킹은 JavaScript에서 관찰되고 실행되는 주어진 이름의 CSS3 애니메이션 이벤트를 사용하는 것입니다.


4

한 가지 방법은, 같다 (단지 파이어 폭스와 크롬에서 테스트하지만) 신뢰성은 수신 자바 스크립트를 사용하는 것입니다 animationend(또는 낙타 표기법, 그리고 형제, 접두사 animationEnd) 이벤트 및에 단명 (데모 0.01 초)에 애니메이션을 적용 추가하려는 요소 유형. 물론 이것은 onCreate이벤트가 아니라 ( 호환되는 브라우저에서) onInsertion이벤트 유형에 가깝습니다. 다음은 개념 증명입니다.

$(document).on('webkitAnimationEnd animationend MSAnimationEnd oanimationend', function(e){
    var eTarget = e.target;
    console.log(eTarget.tagName.toLowerCase() + ' added to ' + eTarget.parentNode.tagName.toLowerCase());
    $(eTarget).draggable(); // or whatever other method you'd prefer
});

다음 HTML 사용 :

<div class="wrapper">
    <button class="add">add a div element</button>
</div>

그리고 (아래의 Fiddle에 있지만 축약 된 접두사 버전 제거됨) CSS :

/* vendor-prefixed alternatives removed for brevity */
@keyframes added {
    0% {
        color: #fff;
    }
}

div {
    color: #000;
    /* vendor-prefixed properties removed for brevity */
    animation: added 0.01s linear;
    animation-iteration-count: 1;
}

JS Fiddle 데모 .

분명히 CSS는 jQuery에서 사용되는 선택기뿐만 아니라 관련 요소의 배치에 맞게 조정할 수 있습니다 (실제로 가능한 삽입 지점에 가까워 야 함).

이벤트 이름 문서 :

Mozilla   |  animationend
Microsoft |  MSAnimationEnd
Opera     |  oanimationend
Webkit    |  webkitAnimationEnd
W3C       |  animationend

참조 :


4

나를 위해 몸에 바인딩이 작동하지 않습니다. jQuery.bind ()를 사용하여 문서에 바인딩합니다.

$(document).bind('DOMNodeInserted',function(e){
             var target = e.target;
         });

1

어떤 경우에는 이것이 효과가 있다는 것을 언급 할 가치가 있다고 생각합니다.

$( document ).ajaxComplete(function() {
// Do Stuff
});

1

대신에...

$(".class").click( function() {
    // do something
});

당신은 쓸 수 있습니다...

$('body').on('click', '.class', function() {
    // do something
});

0

<select>ID로 만들고 문서에 추가하고 호출하십시오..combobox

  var dynamicScript='<select id="selectid"><option value="1">...</option>.....</select>'
  $('body').append(dynamicScript); //append this to the place your wanted.
  $('#selectid').combobox();  //get the id and add .combobox();

이것은 트릭을 할 것입니다 .. 원하는 경우 선택을 숨기고 .combobox표시 한 후에 .. 또는 그렇지 않으면 찾기를 사용하십시오 ..

 $(document).find('select').combobox() //though this is not good performancewise

-1

angularjs를 사용하는 경우 고유 한 지시문을 작성할 수 있습니다. bootstrapSwitch와 동일한 문제가 발생했습니다. 나는 $("[name='my-checkbox']").bootstrapSwitch(); 자바 스크립트 에서 호출해야 하지만 그 당시에 내 html 입력 개체가 생성되지 않았습니다. 그래서 나는 자신의 지시문을 작성하고 다음을 사용하여 입력 요소를 만듭니다. <input type="checkbox" checkbox-switch>

지시문에서 요소를 컴파일하여 자바 스크립트를 통해 액세스하고 jquery 명령을 실행합니다 (명령과 같은 .combobox()). 매우 중요한 것은 속성을 제거하는 것입니다. 그렇지 않으면이 지시문이 자신을 호출하고 루프를 작성합니다.

app.directive("checkboxSwitch", function($compile) {
return {
    link: function($scope, element) {
        var input = element[0];
        input.removeAttribute("checkbox-switch");
        var inputCompiled = $compile(input)($scope.$parent);
        inputCompiled.bootstrapSwitch();
    }
}
});

AngularJS가 아닌 jQuery와 관련된 질문입니다. 솔루션은 jQuery 및 jQuery 플러그인으로 제한되어야합니다.
James Dunne
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.