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

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

ただいまの
回答率

88.33%

JavaScriptの関数の実行タイミングを一番最後にしたい

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 629

m-88888888

score 13

やりたいこと

Ruby on Railsを使ってWebアプリケーションを作成しています。
nested_form_fieldsというgemを使って、動的に画像アップロードフォームを含めた入力フォームを動的に追加できる機能を実装しており、この追加された画像アップロードフォームのそれぞれに対して画像プレビュー機能をつけたいと考えています。

イメージ画像
イメージ説明

// _form.html.slim
= f.nested_fields_for :gears, wrapper_tag: :div do |g|
  .item
    .row
      .col-6
        .form-group
          = g.label :gear_image
          - if g.object.gear_image?
            = image_tag(g.object.gear_image.url, id: 'preview__nested_field_for_replace_with_index__', class: 'gear_image')
          - else
            = image_tag('nofile.jpg', id: 'preview__nested_field_for_replace_with_index__', class: 'gear_image')
          = g.file_field :gear_image, class: "form-control-file gear-file-form"
      .col-6
        .form-group
          = g.label :name
          = g.text_field :name, class: "form-control"
        .form-group
          = g.label :brand
          = g.text_field :brand, class: "form-control"
        .form-group
          = g.label :kind
          = g.select :kind, gear_type_list, { include_blank: true }, class: "form-control"
        .form-group
          = g.label :model_year
          = g.text_field :model_year, class: "form-control"
        = g.remove_nested_fields_link '削除', class: 'btn btn-danger', role: 'button'
= f.add_nested_fields_link :gears, '+', class: 'btn btn-primary', role: 'button', id: 'add-form'
// application.js
document.addEventListener('DOMContentLoaded', function () {
  var index = 1;
  var fuga = '#preview';

  document.getElementById('add-form').addEventListener("click", function () {
    index += 1;
    // とりあえず以下2通り試しましたがフォーム作成前に実行されてしまいます。
    hogehoge(index);  // 1
    window.onload = hogehoge(index); // 2
  }, false);

  // 関数①
  function hogehoge(index) {
    for (var i = 0; i < index; i++) {
      (function (j) {
        fuga += j.toFixed();
        var id = 'article_gears_attributes_' + j + '_gear_image';
        document.getElementById(id).addEventListener("change", function (evt) {
          var file = evt.target.files;
          var reader = new FileReader();
          reader.readAsDataURL(file[0]);
          reader.onload = function () {
            document.querySelector(fuga).src = reader.result;
          }
        }, false);
      }(i));
    }
  };
  window.onload = hogehoge(index);
});

問題点

JavaScriptで

  1. フォームの数だけ画像アップロードフォームにイベントを追加する関数hogehogeを定義・・・①
  2. ページ読み込み時に①を実行
  3. フォームの追加ボタン(画像では+ボタン)を押下した時に①の関数hogehogeを再実行

という流れを思い浮かべていたのですが、3.でフォームがnested_form_fieldsによって追加される前に
①の関数hogehogeが実行されてしまい、Uncaught TypeError: Cannot read property 'addEventListener' of nullを吐いてしまいます。

フォームが追加された後に関数hogehogeを実行させるようにしたいのですが、なにか良いやり方はないでしょうか?

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 1

checkベストアンサー

+1

こんにちは、m-88888888さん

質問拝見しました。

早速ですが、問題点の3は、おそらくwindow.onloadに、hogehogeメソッドを実行した返り値を渡すようになっているからだと思います。
window.loadに渡せるのは、関数自体になるので、質問と同じ条件でindexを渡した状態で関数を渡したいのであれば、bindメソッドを利用すると良いと思います。
こうすれば、 DOMContentLoadedイベント時に、window.onloadがセットアップされ、loadイベントが完了したあとに、indexを捕捉した状態でhogehogeメソッドが実行されます。

window.load
Function.prototype.bind()

// application.js
document.addEventListener('DOMContentLoaded', function () {

  ...(省略)

  window.onload = hogehoge.bind(this, index);
});

以上、参考になれば、幸いです。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2019/12/31 17:39

    ご指摘の通り、bindメソッドを使用したところエラーの表示までは解消されましたが、肝心の関数hogehogeは実行された形跡が見られませんでした。
    おそらく今回の問題とはまた別?だと思うので、こちらは自分で取り組んでみます。
    この度はご回答いただき誠にありがとうございました!

    キャンセル

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

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

関連した質問

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