質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.50%

JavaScriptで読み込んだHTMLの一部を書き換えてBodyに追加したい

解決済

回答 2

投稿

  • 評価
  • クリップ 2
  • VIEW 5,480

score 7

前提・実現したいこと

JavaScript初心者です。
Twitterのクライアントアプリを作っているのですが、
外部に用意したツイート表示用のHTMLをJavaScript(jQuery)で読み込んで、
名前・アイコン・テキスト(本文)の部分をAPIで取得したものに差し替えてから、
Bodyの指定した位置に挿入したいです。

例えば以下のような感じです。
ツイート表示用のHTMLは"template.html"、
名前・テキストのタグのIDはそれぞれ "tweet-name", "tweet-text" です。

<!DOCTYPE html>
  <head></head>
  <body>
    <div id="tweets-space"></div> <!-- ここに挿入したい -->
    <script src="/node_modules/jquery/dist/jquery.min.js"></script>
    <script>
      function InsertTweets(tweets /*取得したツイートのリスト*/) {
        let template = $('<div>').load("template.html");
        for(let i = 0; i < tweets.length; ++i) {
          tweet_element = template.clone();
          // 名前・テキストを差し替える(ここが分からない)
          tweet_element.find("#tweet-name").text(tweets[i].name) 
          tweet_element.find("#tweet-text").text(tweets[i].text)
          $('#tweets-space').append(tweet_element[0]);
        }
      }
    </script>
  </body>
</html>

発生している問題

外部のHTMLを $('#hoge').load("fuga.html"); で読み込むところまでは出来たのですが、
読み込んだHTMLの特定の要素の属性・textを書き換える方法が分かりません。
そもそもforの中で要素をappendしても1つしか挿入されません。
そしてcloneしたものをconsole.log(cloned[0])で表示しても中身が空っぽのdivタグです。

APIで取得するところまではできていて、あとはHTMLで表示させるだけなので、
jQueryを使わない方法でもいいのでご教示下さい。よろしくお願いします。m(_ _)m

補足情報(言語/FW/ツール等のバージョンなど)

jQueryのバージョンは3.2.1です。
webサーバーはFlask、クライアント側はelectronです。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+4

http://api.jquery.com/load/
更にjQuery.loadのソースコードを見るとAjaxという非同期通信が使われている。

新たにHTMLリクエスト等を発射した場合、
リクエストの結果が返ってくるまで何の動作も出来ずに待ちぼうけになってしまう。
通信やファイルの読み書きといった結果が反映されるまで遅い処理を実行する時は、
通信結果を待たずに次の行を実行するという動作をする。

「えー、それじゃ困る、通信終わってから決めた処理をして欲しい」というケースはもちろんあるよね。
残りの処理を関数化して引数として渡しておき、「通信終わったらこの関数を実行してね」とお願いするのが慣習


さて上記前提条件を元にコードをみていこう。
リファレンスを見ると下記のような記述がある。

$( "#success" ).load( "/not-here.php", function( response, status, xhr ) {
  if ( status == "error" ) {
    var msg = "Sorry but there was an error: ";
    $( "#error" ).html( msg + xhr.status + " " + xhr.statusText );
  }
});

loadメソッドの第2引数に、やりたい処理を関数に包んで定義してある。
これと同じことをやろう。

let template = $('<div>').load("template.html");
for(let i = 0; i < tweets.length; ++i) {
  tweet_element = template.clone();
  // 名前・テキストを差し替える(ここが分からない)
  tweet_element.find("#tweet-name").text(tweets[i].name) 
  tweet_element.find("#tweet-text").text(tweets[i].text)
  $('#tweets-space').append(tweet_element[0]);
}

こうではなく、こうだ!

let template = $('<div>').load("template.html", function (response, status, xhr) {
  for(let i = 0; i < tweets.length; ++i) {
    tweet_element = template.clone();
    // 名前・テキストを差し替える(ここが分からない)
    tweet_element.find("#tweet-name").text(tweets[i].name) 
    tweet_element.find("#tweet-text").text(tweets[i].text)
    $('#tweets-space').append(tweet_element[0]);
  }
}

一旦これで様子を見よう。
このように処理を変えた事で、tweet_element = template.clone();の行の実行タイミングがAjax通信完了後に変わる。
つまり、関数に包んだだけで成功している可能性もあるわけだね。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/11/12 15:05

    できました!!!
    非同期だからloadが終わる前に下の処理に行ってたんですね!
    コードを書き換えたら上手く動くようになりました!
    素早い回答ありがとうございます。。

    キャンセル

+4

.load() は取得結果をそのまま返すのではなく、非同期で通信した後、対象DOMに取得結果を格納します。

$( '#result' ).load( 'test.html', function() {
    console.log( 'A' );
    // この部分が実行されるまで$( '#result' )には'test.html'の内容が入っていない
} );
console.log( 'B' );
// B ⇒ A の順で表示される

.get() でとってコールバック関数内で $('#tweets-space').append(); をするほうが良いでしょう。


【.load() | jQuery API Documentation】
http://api.jquery.com/load/

【.load() | jQuery 1.9 日本語リファレンス | js STUDIO】
http://js.studio-kingdom.com/jquery/ajax/load

【jQuery load() を使って別のページの見出しを表示する | Web Design Leaves】
http://www.webdesignleaves.com/wp/jquery/1593/

【jQuery「.load( )」で簡単にhtmlパーツをインクルードする方法|プラカンブログ | プラスデザインカンパニー【大阪・東京 ホームページ・WEB制作】】
http://www.plusdesign.co.jp/blog/?p=4832

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/11/12 15:08 編集

    回答ありがとうございます!
    第二引数でコールバック関数を指定しないといけないんですね。
    色々記事を漁ってたんですが見落としていたかもしれないです。。
    DOMというのがよくわかっていないんですが、clone後のオブジェクトが空の理由を調べていたら
    DOMに格納されていないからというのを見ました。こういうことだったんですね。。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.50%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る