.append後のjQuery関数


90

jQuery .appendが完全に終了した後に関数を呼び出す方法は?

次に例を示します。

$("#root").append(child, function(){
   // Action after append is completly done
});

問題:複雑なDOM構造が追加されると、追加関数コールバック内のルート要素の新しいサイズの計算が間違っています。DOMはまだ完全にロードされておらず、追加された複雑なDOMの最初の子だけであることが前提です。


イベントを細かくチェーンする必要があります。append()時間はほとんどかかりません。
Bojangles、

stackoverflow.com/q/8840580/176140(Webkitブラウザーではdom 'reflow')を参照してください
schellmax

これは役に立つかもしれません:stackoverflow.com/a/1489987/1375015
Konstantin Schubert

回答:


70

ここには多くの有効な回答がありますが、実際に機能する理由を説明するものはありません。

JavaScriptでは、タイムアウトまたは間隔を使用して非同期であると明示的に指定しない限り、コマンドは一度に1つずつ、実行順に同期して実行されます。

つまり、.appendメソッドが実行され、そのメソッドがそのジョブを完了するまで、他に何も(存在する可能性のあるタイムアウトや間隔を無視して)実行されません。

まとめると、は.append同期的に実行されるため、コールバックは必要ありません。


39
これはすべて当てはまりますが、ここに私の問題があります。複雑なDOMを追加し、追加直後にルート要素の新しいサイズを計算しますが、ここで間違った数値を取得しました。そして、問題はこれであると考えてください:DOMはまだ完全にロードされておらず、最初の子のみです(.append( "<div id =" child "> <div id =" subChild_with_SIZE "> </ div> </ div>"))
DavidHorák、

@JinDave、あなたが言及しているこのサイズは何ですか?それは子供の量、親の身長ですか、それともあなたが計算する必要があるものですか?
mekwall

1
@マーカス・ekwall jsfiddle.net/brszE/3それだけでコードを動作していない、方法を書いています、
デヴィッドHorák

22
@DavidHorákでは、なぜこれが受け入れられた答えなのでしょうか。それは!変更が発生していても、完全なリフローはかなりこれは32のアップ票を持って驚かれるまで、コードがブロックしないというのは本当だ(またはそれ私ではないとしてもリフロー原因)の答えのようなものは[こちら](stackoverflow.com/questions/ 8840580 /…)鉱石関連がある可能性があります。
Andreas

17
アンドレアスに同意する、この答えは正しくない。問題は、appendが返されたとしても、要素がDOMでまだ使用できない可能性があることです(ブラウザーに依存し、一部のブラウザーでは機能し、他のブラウザーでは機能しません)。タイムアウトを使用しても、要素がDOMにあることは保証されません。
Severun、2016年

19

さて、私はサイズの再計算でまったく同じ問題を抱えており、何時間もの頭痛の後で、.append()厳密に同期する動作に同意する必要があります。少なくともGoogle Chromeではそうです。次のコードを参照してください。

var input = $( '<input />' );
input.append( arbitraryElement );
input.css( 'padding-left' );

Firefoxでpadding-leftプロパティは正しく取得されますが、Chromeでは空です。私が思う他のすべてのCSSプロパティと同様に。いくつかの実験を行った後、CSSの「getter」setTimeout()を10ミリ秒の遅延でラップすることで解決する必要がありました。あなたがこの問題をより良く解決する方法を知っている人がいたら、私はとても感謝しています。


15
これは私を助けてくれました:stackoverflow.com/q/8840580/176140-つまり、append()は同期的ですが、DOMの更新はそうではありません
schellmax

その場合、setTimeoutは見苦しくありません(10msだけが醜いです)。「dom」操作をリクエストするたびに、chromeはコードが終了するのを待ってから実行します。したがって、item.hideの後にitem.showを呼び出しても、何も実行されません。実行中の関数が終了すると、変更がDOMに適用されます。続行する前に「dom」の更新を待つ必要がある場合は、CSS / DOMアクションを実行してから、settimeout(function(){次の操作});を呼び出します。settimeoutは、vb6の古き良き「doevents」のように機能します。待機中のタスク(DOMの更新)を実行するようブラウザに指示し、その後、コードに戻ります。
foxont​​herock 2017

.ready()はるかに優れたエレガントなソリューションを利用した答えをご覧ください。
Mark Carpenter Jr

19

Marcus Ekwallは、appendの同時性については完全に正しいですが、奇妙な状況では、次のコード行を実行したときに、ブラウザーによってDOMが完全にレンダリングされないこともあります。

このシナリオでは、shadowdiverソリューションは正しい線に沿って-.readyを使用して-ですが、元の追加への呼び出しをチェーンするのはかなり面倒です。

$('#root')
  .append(html)
  .ready(function () {
    // enter code here
  });

これは絶対に誤りであり、あらゆる状況で役に立ちません。api.jquery.com/ready
Kevin B

こんにちは、ケビン。
ダニエル-SDSグループ

.readyを使用して追加の要素が「レンダリング」されるのを待つことは、ドキュメントがまだ準備ができていない場合にのみ、単にsettimeoutを使用する場合よりもまったくメリットがありません。ドキュメントの準備ができている場合、コードは同期的に実行されるため、有用な影響はありません。
Kevin B

準備は、追加されたドキュメントが読み込まれるのを待つのではなく、DOM全体が読み込まれるのを待ちます。この回答を書いてから約3年が経ちましたが、上のシャドウダイバーについてはもっとコメントしていると思いますが、現時点ではコメントする機能がありませんでした。
ダニエル-SDSグループ

1
実際、これは予想よりもうまく機能します。ここで他のどの回答よりも優れています。
ブルー

8

ここですべての答えに驚いています...

これを試して:

window.setTimeout(function() { /* your stuff */ }, 0);

タイムアウト0に注意してください。任意の数ではありません...私が理解しているように(私の理解は少し不安定かもしれません)、2つのjavascriptイベントキューがあります-マクロイベント用とマイクロイベント用です。「より大きな」スコープキューは、UI(およびDOM)を更新するタスクを保持し、microキューはクイックタスクタイプの操作を実行します。

また、タイムアウトを設定しても、コードがその指定された値で正確に実行されるとは限らないことに注意してください。これにより、基本的には関数が上位のキュー(UI / DOMを処理するキュー)に入れられ、指定された時間の前に実行されなくなります。

つまり、タイムアウトを0に設定すると、JavaScriptのイベントキューのUI / DOM部分に配置され、次の機会に実行されます。

これは、DOMが以前のすべてのキュー項目(を介して挿入されるなど)で更新され$.append(...);、コードが実行されると、DOMが完全に使用可能になることを意味します。

ps-私はこれをJavaScript NinjaのSecrectsから学びました-優れた本:https : //www.manning.com/books/secrets-of-the-javascript-ninja


setTimeout()理由がわからないまま何年も追加しています。説明ありがとう!
1

5

私は誰かに役立つかもしれない別のバリアントがあります:

$('<img src="http://example.com/someresource.jpg">').load(function() {
    $('#login').submit();
}).appendTo("body");

1
これは非推奨で削除されたと考える人にとっては正しいですが、次のように使用でき...on('load', function(){ ... ます:stackoverflow.com/a/37751413/2008111
caramba

5

私は同じ問題に遭遇し、簡単な解決策を見つけました。追加機能を呼び出した後にドキュメントを準備します。

$("#root").append(child);
$(document).ready(function () {
    // Action after append is completly done
});


いいね。これは私にとってはうまくいきました(私はハンドルバーとJSONを使用してHTMLを追加していました、そしてもちろん通常のdocument.readyはそれらすべてのために早すぎます)。
キャサリンオズボーン

1
@KatharineOsborneこれは「通常のdocument.ready」と同じです。document.readyは、1つの特定のシナリオでのみ呼び出されます。異なる方法で使用しても、動作は異なります。
ケビンB

さて、コメントを書いてから1年以上になりますが、IIRC、これを呼び出す場所のコンテキストは重要です(つまり、関数内)。私は後ろに掘るために任意のより多くのそれへのアクセスを持っていないので、コードがあるため、クライアントに渡されました。
キャサリン・オズボーン

5

を使用MutationObserverすると、jQuery appendメソッドのコールバックのように機能できます。

別の質問で説明しましたが、今回は最新のブラウザの例のみを示します。

// Somewhere in your app:
var observeDOM = (() => {
    var MutationObserver = window.MutationObserver || window.WebKitMutationObserver;

    return function(obj, callback){
        if( MutationObserver ){
            // define a new observer
            var obs = new MutationObserver(function(mutations, observer){
                if( mutations[0].addedNodes.length || mutations[0].removedNodes.length )
                    callback(mutations);
            });
            // have the observer observe foo for changes in children
            obs.observe( obj, { childList:true, subtree:true });

            return obs;
        }
    }
})();

//////////////////
// Your code:

// setup the DOM observer (on the appended content's parent) before appending anything
observeDOM( document.body, ()=>{
    // something was added/removed
}).disconnect(); // don't listen to any more changes

// append something
$('body').append('<p>foo</p>');

+1。すべての回答のうち、あなたの答えが最もよく合います。しかし、それは私の場合には機能しませんでした。テーブルにさまざまな行を追加しました。無限ループになるためです。テーブルをソートするプラグインはDOMを変更するため、オブザーバーを無限に呼び出します。
アゼベド2018年

@Azevedo-なぜそれが無限になるのですか?有限だと思います。とにかく、少しクリエイティブになることで、並べ替え機能を追加された行の「イベント」から分離できます。方法があります。
vsync 2018年

並べ替えプラグインがテーブルを並べ替えると、オブザーバーがトリガーされ(domが変更されます)、並べ替えが再度トリガーされます。今私は考えています...テーブルの行をカウントして、行カウンターが変更された場合にのみオブザーバーにソーターを呼び出させることができます。
アゼベド2018年

3

私はこれはうまく答えられたと思いますが、これは「subChild_with_SIZE」の処理にもう少し具体的です(それが親からのものである場合は、それをどこからでも適用できます)

$("#root").append(
    $('<div />',{
        'id': 'child'
    })
)
.children()
.last()
.each(function() {
    $(this).append(
        $('<div />',{
            'id': $(this).parent().width()
        })
    );
});

2

$.when($('#root').append(child)).then(anotherMethod());


8
$.whenpromiseオブジェクトを返すオブジェクトに対してのみ機能します
Rifat

動作していますが、コンソールにエラーが表示されます。「機能ではありません」
Karan Datwani '17

1
これは、anotherMethod()すぐに呼び出すためにのみ機能します。コールバックとして渡されていません。
yts

これは意味がありません。
ケビンB

1

jquery追加関数はjQueryオブジェクトを返すので、最後にメソッドにタグを付けることができます

$("#root").append(child).anotherJqueryMethod();

私は私に.append後のカスタムJavaScript関数を呼び出す必要が、私は、ルートの再計算サイズを必要とする
デビッドHorák

jQueryの各メソッドを使用することもできますが、appendは同期メソッドであるため、次の行で必要なことを何でも実行できます。
Dve

@JinDave、正確に何を再計算する必要がありますか?子供の量、親の身長、またはサイズの意味は何ですか?
mekwall、

0

画像やその他のソースの場合、それを使用できます。

$(el).one('load', function(){
    // completed
}).each(function() {
    if (this.complete)
        $(this).load();
});

0

最もクリーンな方法は、段階的にそれを行うことです。各機能を使用して、各要素をくまなく調べます。その要素が追加されたらすぐに、それを後続の関数に渡してその要素を処理します。

    function processAppended(el){
        //process appended element
    }

    var remove = '<a href="#">remove</a>' ;
    $('li').each(function(){
        $(this).append(remove);   
        processAppended(this);    
    });​

-1

モバイルデバイス用のHTML5のコーディング中にこの問題が発生しました。.append()メソッドがDOMの変更をすぐに反映しないため(JSが失敗するため)、一部のブラウザーとデバイスの組み合わせでエラーが発生しました。

この状況に対する迅速で汚い解決策は次のとおりです。

var appint = setInterval(function(){
    if ( $('#foobar').length > 0 ) {
        //now you can be sure append is ready
        //$('#foobar').remove(); if elem is just for checking
        //clearInterval(appint)
    }
}, 100);
$(body).append('<div>...</div><div id="foobar"></div>');

コードコンストラクターの終了を待機するために間隔を使用しないでください。それは完全に信頼できません。
Gabe Hiemstra 2016年

-1

はい、任意のDOM挿入にコールバック関数を追加できます 。JQueryのドキュメントを確認してくださいhttp : //api.jquery.com/append/ そして、実際的な同様の例を次に示します:http : //www.w3schools.com/jquery/ tryit.asp?filename = tryjquery_html_prepend_func
$myDiv.append( function(index_myDiv, HTML_myDiv){ //.... return child })



w3schoolsの例をいじると、2番目のパラメーターをチェックして、.prepend()メソッドを次のように置き換えることができます:$( "p")。prepend(function(n、pHTML){return "<b> This p element </ b>(\" <i > "+ pHTML +" </ i> \ ")<b>のインデックスは" + n + "</ b>です。";
Pedro Ferreira

1
あなたはその例の目的を明確に理解していません。それは、コンテンツが追加されたというコールバックではなく、追加されるものを返すコールバック関数です。
vsync 2016

@vsync:正確に。あなたは明らかに私の答えを理解していませんでした。「子」は追加されたものであり、追加されたときではありません
ペドロフェレイラ

-1

最近、似たような問題に遭遇しました。私にとっての解決策は、コレクションを再作成することでした。実演してみましょう:

var $element = $(selector);
$element.append(content);

// This Doesn't work, because $element still contains old structure:
$element.fooBar();    

// This should work: the collection is re-created with the new content:
$(selector).fooBar();

お役に立てれば!


それは私を助けませんでした。:(
Pal

-1

jqueryでは、追加した直後に使用できます

$(function(){
//code that needs to be executed when DOM is ready, after manipulation
});

$()は、DOM対応のコールバックを登録する(関数が渡される場合)、またはDOMから要素を返す(セレクター文字列または要素が渡される場合)関数を呼び出します。

あなたはもっとここに見つけることができます
jQueryので$と$()との差を
http://api.jquery.com/ready/


-2

私はそれが最良の解決策ではないことを知っていますが、ベストプラクティス:

$("#root").append(child);

setTimeout(function(){
  // Action after append
},100);

8
これは良い習慣だとは思いません。100は任意の数であり、イベントにはさらに時間がかかる可能性があります。
JasTonAChair 2015

1
行き方が間違っています。必ずしも
100ミリ秒

これが機能する理由の説明については、ここで私の回答を参照してください(数値は100ではなく0である可能性があります):stackoverflow.com/questions/6068955/…–
jleach

1
少なくとも.readyを使用したここでの回答よりも良い方法です。
Kevin B

-4
$('#root').append(child);
// do your work here

Appendにはコールバックがなく、これは同期的に実行されるコードです-実行されないリスクはありません


3
このようなコメントが多すぎるので、役に立ちません。@davidは失敗しました。はい、JSは同期していますが、DOMの更新には時間が必要です。DOMの追加要素を操作する必要があるが、要素がDOMにまだレンダリングされていない場合、追加が行われても、新しい操作は機能しません。。(例:$( '#要素')上の()。
NoobishPro

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.