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

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

新規登録して質問してみよう
ただいま回答率
85.48%
JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

jQuery

jQueryは、JavaScriptライブラリのひとつです。 簡単な記述で、JavaScriptコードを実行できるように設計されています。 2006年1月に、ジョン・レシグが発表しました。 jQueryは独特の記述法を用いており、機能のほとんどは「$関数」や「jQueryオブジェクト」のメソッドとして定義されています。

Q&A

解決済

2回答

2492閲覧

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

akiiro_

総合スコア19

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

jQuery

jQueryは、JavaScriptライブラリのひとつです。 簡単な記述で、JavaScriptコードを実行できるように設計されています。 2006年1月に、ジョン・レシグが発表しました。 jQueryは独特の記述法を用いており、機能のほとんどは「$関数」や「jQueryオブジェクト」のメソッドとして定義されています。

0グッド

0クリップ

投稿2018/11/06 10:39

編集2018/11/06 12:19

前提・実現したいこと

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

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

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

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

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

該当のソースコード

HTML

1<input type="text" class="profile-edit-add-tag-myself-search js-profile-edit-add-skill-tag-myself-search"> 2<ul class="profile-edit-suggest-list js-profile-edit-skill-suggest-list"></ul>

JavaScript

1 2 var $addMyTagSearch = $('.js-profile-edit-add-skill-tag-myself-search'); 3 var $suggestList = $('.js-profile-edit-skill-suggest-list'); 4 5 // form内でkeyupされた時 6 $addMyTagSearch.on('keyup', function (e) { 7 var inputCharacter = $(this).val(); 8 var inputCharacterLength = inputCharacter.length; 9 10 $suggestList.show(); 11 $('.profile-edit-suggest-list-item').remove(); 12 $.ajax({ 13 //省略 14 } 15 }) 16 .then( 17 function (data) { 18 19 for (var item in data) { 20 var dataName = data[item].name; 21 var dataCount = data[item].count; 22 var dynamicSuggestListItem = $('<li class="profile-edit-suggest-list-item js-profile-edit-suggest-list-item"></li>'); 23 24 $suggestList.append(dynamicSuggestListItem); 25 dynamicSuggestListItem.append('<p class="profile-edit-suggest-list-item-character">' + dataName + '</p>').append('<span class="profile-edit-suggest-list-item-registered">' + dataCount + '</span>'); 26 27 // 5つまで生成 28 $('.js-profile-edit-suggest-list-item:nth-child(n+6)').remove(); 29 } 30 }, 31 function () { 32 alert('通信に失敗しました。恐れ入りますが、再度操作をお願いいたします。'); 33 } 34 ); 35 })

試したこと

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

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

for of
$.each()

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

setTimeout()

  • setTimeout(function () {
    for (var item in data) {
    //省略
    }
    }

という感じで使用しました。
ここだとインデント効かないので少し見辛くなってます。
すみません。

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

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

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

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

think49

2018/11/06 12:16 編集

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

2018/11/06 12:20

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

回答2

0

ベストアンサー

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

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

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

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

HTML

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

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

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

JavaScript

1$('.profile-edit-suggest-list-item').remove(); // 削除 2$.ajax({ 3 //省略 4 } 5 }) 6 .then( 7 function (data) { 8// ...(中略)... 9 $suggestList.append(dynamicSuggestListItem); // 追加

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

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

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

フローチャート

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

Re: akiiro_ さん

投稿2018/11/06 11:37

編集2018/11/06 12:37
think49

総合スコア18162

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2018/11/06 12:23 編集

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

2018/11/06 12:30

>think49様 回答ありがとうございます。 先程、より遅い入力のgifを貼りましたのでご確認いただければと思います。 それと重複チェックの事やフローチャートのやり方など教えて頂きありがとうございます。 $('.profile-edit-suggest-list-item').remove();で子ノードは群はkeyupする度に削除しています。 重複内容を表示しない事に関してはしていないので試してみます。 その前に図式化してみたいと思います!
think49

2018/11/06 12:34

親記事に「削除/追加タイミングの問題」を追記しました。 通常、JavaScriptでは他の処理に割り込まれる事はありませんが、非同期処理を間に入れると割り込まれます。 削除から追加するまでの過程は連続処理になるようコードを工夫して下さい。
akiiro_

2018/11/06 12:39

> RYNO様 回答ありがとうございます。 formの入力文字 === suggestListのliのtext()という事でしょうか? なぜ逆転してしまうのか、わからないです。
think49

2018/11/06 12:40

To: RYNO さん 仰ることは分かります。 解決手段としては、実行中の通信を配列管理し、現在の通信よりも前の通信リクエストは全てabort()すれば、良いと思います。
think49

2018/11/06 12:45

To: akiiro_ さん RYNO さんが指摘されているのは、"web" と入力した時、「we" のサジェスト通信」より前に「"web" のサジェスト通信」が完了してしまった場合に、処理順の逆転が起きるという事です。 このコードでは「通信が完了した順」に実行するだけですので、先に「"web" の通信が完了」してしまうと、「"web" のサジェスト結果出力→"we" のサジェスト結果出力」となります。
akiiro_

2018/11/06 12:48

> think49様 ありがとうございます! 非同期処理より他の通常の関数やらが先に処理されるからという事でしょうか?
akiiro_

2018/11/06 12:52

>think49様 そんな事あるんですね! だから、入力した文字と現在表示されている文字の確認がいるという事なんですね。
think49

2018/11/06 12:53 編集

To: akiiro_ さん > 非同期処理より他の通常の関数やらが先に処理されるからという事でしょうか? 違います。 非同期通信A→非同期通信Bの順番で実行しても処理完了タイミングは「A→B」「B→A」のどちらになるか不定ということです。 本題に戻りますか、RYNO さんが指摘された問題は、今回の問題とは別種の問題ですので、まずは目の前の問題を解決させてください。 追加する直前に削除すれば、すぐに解決すると思うのですが。
akiiro_

2018/11/06 12:59

> think49様 教えて頂きありがとうございます。 失礼いたしました。 以後気をます。 無事解決いたしました。 丁寧な回答本当にありがとうございました。
akiiro_

2018/11/06 13:01

> think49 非同期通信について勉強してみます!
退会済みユーザー

退会済みユーザー

2018/11/06 14:35 編集

To: think49さん お手数かけてすみません。解決策は、abort()を使った方がスマートですね。 To: akiiro_さん すでにthink49さんが回答してある通りです。(think49さん、ありがとうございます。)
guest

0

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

投稿2018/11/06 10:44

yambejp

総合スコア114769

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

akiiro_

2018/11/06 12:42

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問