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

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

ただいまの
回答率

88.59%

formに一定の速度以上で入力するとajaxから生成した要素が複数回表示される。

解決済

回答 2

投稿 編集

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

akiiro_

score 18

 前提・実現したいこと

formでkeyupする度にajaxで要素を生成。

今回のタスクで何回か質問させていただいています。
ajaxを触るのは今回が初めてで四苦八苦している半年目のwebDesignerです。

suggest機能を作成しています。
suggestはul > liで作成しています。
ulは静的。
liはajaxで動的に生成しています。
liは5個まで生成されます。

 発生している問題・エラーメッセージ

入力速度が早いと同じデータのliがulの中に表示される。
さらに早いとliが生成されない。

 該当のソースコード

<input type="text" class="profile-edit-add-tag-myself-search js-profile-edit-add-skill-tag-myself-search">
<ul class="profile-edit-suggest-list js-profile-edit-skill-suggest-list"></ul>
  var $addMyTagSearch = $('.js-profile-edit-add-skill-tag-myself-search');
  var $suggestList = $('.js-profile-edit-skill-suggest-list');

  // form内でkeyupされた時
  $addMyTagSearch.on('keyup', function (e) {
    var inputCharacter = $(this).val();
    var inputCharacterLength = inputCharacter.length;

    $suggestList.show();
    $('.profile-edit-suggest-list-item').remove();
    $.ajax({
      //省略
      }
    })
    .then(
      function (data) {

        for (var item in data) {
          var dataName = data[item].name;
          var dataCount = data[item].count;
          var dynamicSuggestListItem = $('<li class="profile-edit-suggest-list-item js-profile-edit-suggest-list-item"></li>');

          $suggestList.append(dynamicSuggestListItem);
          dynamicSuggestListItem.append('<p class="profile-edit-suggest-list-item-character">' + dataName + '</p>').append('<span class="profile-edit-suggest-list-item-registered">' + dataCount + '</span>');

          // 5つまで生成
          $('.js-profile-edit-suggest-list-item:nth-child(n+6)').remove();
        }
      },
      function () {
        alert('通信に失敗しました。恐れ入りますが、再度操作をお願いいたします。');
      }
    );
  })

 試したこと

ajaxの回し方に着目してアプローチしました。
以下を組み合わせるなどして試行錯誤しました。

  1. for inが悪いと思って以下に書き換えた。
    for of
    $.each()

  2. ajaxが何回も繰り返されてしまうと思い以下を使用した。
    setTimeout()

  • setTimeout(function () {
    for (var item in data) {
    //省略
    }
    }
    という感じで使用しました。
    ここだとインデント効かないので少し見辛くなってます。
    すみません。

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

ここにより詳細な情報を記載してください。
イメージ説明
より遅い入力

よろしくお願いいたします。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

質問への追記・修正、ベストアンサー選択の依頼

  • think49

    2018/11/06 20:30 編集

    入力速度の多寡に関わらず、重複してサジェストされているように見えるのですが、まだ開示されていない "bew", "web" 以上に遅い入力結果があるのでしょうか。

    キャンセル

  • akiiro_

    2018/11/06 21:20

    より遅い入力のgifを貼りました。 よろしくお願いします。

    キャンセル

回答 2

checkベストアンサー

+2

 重複チェックがない (※不適切な指摘でした)

貼り付けて頂いたアニメーションgifでは、入力速度の遅い「web」でも「Webディレクター」が重複しているので、入力速度の問題ではないように思います。 重複回避の基本は

  • 重複チェックし、重複内容は挿入しない
  • 常に全削除→全挿入

ですが、掲示されたコードはどちらもせずに、ただ取得したサジェストコンテンツを挿入するだけです。

<ul class="profile-edit-suggest-list js-profile-edit-skill-suggest-list"></ul>

こちらの子ノード群をサジェスト出力する度に削除するか、ul要素ノードそのものを毎回、置換するのが比較的簡単な解決法だと思います。

 削除/追加タイミングの問題

$('.profile-edit-suggest-list-item').remove();  // 削除
$.ajax({
     //省略
     }
   })
   .then(
     function (data) {
// ...(中略)...
         $suggestList.append(dynamicSuggestListItem); // 追加

「非同期通信に削除し、非同期通信に追加していますが、非同期通信中に割り込まれたら、破綻します。
追加する直前に削除して下さい。

単にulリストを消去するだけでは、正常に動作しない場合があります。それは、サジェスト取得の通信のレスポンス順序が逆転する場合です。そのような場合でも厳密な動作を期待するなら、ulリストの消去前に、現在表示されている内容が、現在入力されている内容であるかを確認する必要があります。

こちらも対処する場合、Promiseを配列管理する等して、現在より前にリクエストされた通信が生きているなら、中断させるロジックが必要になります。

 フローチャート

コーディング前にアルゴリズムを手書きで書いたり、フローチャートで図式化する作業を入れると良いと思います。
やみくもにコードを書き換えても、期待通りに動きません。

Re: akiiro_ さん

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/11/06 21:59

    > think49様
    教えて頂きありがとうございます。
    失礼いたしました。
    以後気をます。

    無事解決いたしました。
    丁寧な回答本当にありがとうございました。

    キャンセル

  • 2018/11/06 22:01

    > think49
    非同期通信について勉強してみます!

    キャンセル

  • 2018/11/06 23:29 編集

    To: think49さん
    お手数かけてすみません。解決策は、abort()を使った方がスマートですね。

    To: akiiro_さん
    すでにthink49さんが回答してある通りです。(think49さん、ありがとうございます。)

    キャンセル

+1

非同期処理の宿命なのでpromiseで処理するのが妥当ですが
高速に連続入力されるときにいちいち反応するのは馬鹿らしいので
前回の入力から0.5秒以上たったら検索するとかなんらかのルール付が必要でしょうね

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/11/06 21:42

    > yambejp様
    前回に引き続き回答ありがとうございます。
    setTImeoutをもう一度使用してみようかなと考えているのですがいかがでしょうか?

    キャンセル

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

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

関連した質問

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