動的に作成された要素のjQuery「oncreate」イベント


81

<select>要素を動的に作成してjQueryに変換できる必要があります.combobox()。これは要素作成イベントである必要があります。「クリック」イベントではなく、jQueryを使用できます.on()

それで、このようなものは存在しますか?

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

livequeryは非常に古くなっているため、使用するのは気が進まない。

更新前述のselect / comboboxはajaxを介してjQueryカラーボックス(モーダルウィンドウ)に読み込まれるため、問題-colorboxを使用してのみコンボボックスを開始できますonCompleteが、1つのコンボボックスを変更すると、別のselect /コンボボックスを動的に作成する必要があるため、要素の作成を検出するためのより一般的な方法(selectこの場合)。

UPDATE2問題をさらに説明するために、select/combobox要素を再帰的に作成しました。内部.combobox()には開始コードもたくさんあります。したがって、@ bipenの回答のように従来のアプローチを使用した場合、コードは非常識なレベルに膨れ上がります。これが問題をよりよく説明することを願っています。

UPDATE3皆さんに感謝します。非推奨DOMNodeInsertedになると、DOMミューテーションに空白が残り、この問題の解決策がないことを理解しました。アプリケーションを再考する必要があります。


1
準備ができたイベントである可能性がありますか?$(select).ready(function() { });
Pablo Banderas 2013年

@PabloBanderasreadyは、「DOMが完全にロードされたときに実行する関数を指定する」ために使用されます。(jquery.comから)
Caballero

1
combobox()作成/挿入後ではなく、作成/挿入の時点でメソッドを適用してみませんか?
デビッドは、モニカ

@DavidThomas私の2回目の更新で理由を説明しようとしました
Caballero

だから$(document).on('onComplete', 'select', function(){ // bind here? });?(ただし、明らかに、よりも近い親を使用しdocumentます。)
Davidは

回答:


59

イベントを使用して、コードによってドキュメントに追加されたときonDOMNodeInsertedイベントを取得できます。

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

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

ここでいじる:http//jsfiddle.net/Codesleuth/qLAB2/3/

編集:読んだ後、DOMNodeInsertedブラウザ間で問題が発生しないことを再確認する必要があります。2010年のこの質問は、IEがイベントをサポートしていないことを示唆しているため、可能であればテストしてください。

ここを参照してください:[リンク] 警告!DOMNodeInsertedイベントタイプは、参照と完全性のためにこの仕様で定義されていますが、この仕様では、このイベントタイプの使用は非推奨です


されていない.delegatejQueryのバージョン1.7から非推奨とによってsuperseeded .on
カバレロ2013年

1
ええ、あなたは正しいです。この回答を変更しますが、DOMNodeInserted現在非推奨になっているため、これを使用する必要があるかどうかは正直わかりません。
codesleuth 2013年

on('DOMNodeInserted'この質問を投稿する前に試しました。それは明らかに機能しませんでした。
カバレロ2013年

20
あなたがそれを試したことはあなたの質問ではないので、それは不公平な投票だと思います。いずれにせよ、私はここであなたを助けることはできません。
codesleuth 2013年


20

他のいくつかの回答で述べたように、ミューテーションイベントは非推奨になっているため、代わりにMutationObserverを使用する必要があります。まだ誰もそれについての詳細を与えていないので、ここに行きます...

基本的なJavaScriptAPI

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 });

これにより、オブザーバーが起動します。最初の引数は、オブザーバーが変更を監視するノードです。2番目の引数は、何を監視するかについてオプションです

  • childList 子要素が追加または削除されるのを監視したいという意味です。
  • subtreeは、この要素のサブツリー内の任意の場所で変更を監視するように拡張 する修飾子ですchildList(それ以外の場合は、内の変更を直接確認しますtargetNode)。

他の二つの主要なオプションがほかにchildListあるattributescharacterData、彼らはのように聞こえるかについて平均います。これら3つのうちの1つを使用する必要があります。

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

コールバック内では少し注意が必要です。コールバックはMutationRecordの配列を受け取ります。各MutationRecordは一種類のいくつかの変化を記述することができる(childListattributesまたは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);

これによりdomNodeInsertedjQueryの特別なイベントAPIを使用して、という新しいイベントが作成されます。あなたはそれを次のように使うことができます:

$(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

私のajaxの問題をすべて解決しているように見えるこのソリューションを思いついたところです。

準備ができたイベントの場合、私は今これを使用します:

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+でのみ機能します(現時点では)。

ただし、CSS3アニメーションをサポートするすべてのブラウザー(IE10、Firefox 5以降、Chrome 3以降、Opera 12、Android 2.0以降、Safari 4以降)で機能する「壮大なハック」(著者の言葉は私のものではありません!)があります。ブログのデモをご覧ください。ハックは、JavaScriptで監視および処理される特定の名前のCSS3アニメーションイベントを使用することです。


4

信頼できると思われる1つの方法(FirefoxとChromeでのみテスト済み)は、JavaScriptを使用して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>

そして(以下のフィドルに存在しますが、省略形、接頭辞付きバージョン-削除されました)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;
}

JSFiddleデモ

明らかに、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またはfindを使用できます。

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

-1

anglejsを使用している場合は、独自のディレクティブを作成できます。bootstrapSwitchでも同じ問題が発生しました。$("[name='my-checkbox']").bootstrapSwitch(); javascriptを呼び出す 必要がありますが、その時点でhtml入力オブジェクトは作成されていません。だから私は独自のディレクティブを書き、入力要素を作成します <input type="checkbox" checkbox-switch>

ディレクティブでは、要素をコンパイルしてjavascript経由でアクセスし、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 2016
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.