javascriptでユーザーに求めた作業が終了するまでループを止める方法を知りたい

解決済

回答 1

投稿

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

pig_hedas

score 1

ループ中にボタンを表示し、ボタンが押されるまでループを止める方法について教えてください。

こちらの記事を参考にして、javascriptでボットプログラムを作成しています。

起動されると、ボットはあらかじめ用意されたJsonファイルをajaxで読み出し、配列に代入して順に処理していきます。取り出したデータには"id"や"type"などのオブジェクトがあり、それぞれ処理の順番や要求される動作についてのタグになっています。

下が作成中のプログラムです。

[
  {
    "id":"1",
    "type":"choice",
    "value":["hoge1","hoge2","hoge3"],
    "inline":[
      "id1":"1",
      "id2":"hoge1",
      "type":"text",
      "value":"hoge1が押されました"
    ]
  },
  {
    "id":"2",
    "type":"text",
    "value":"hogehoge"
  }
]
let jdatatmp=[];
let num = 0;
$(document).ready(function(){

    //文字列(html要素)を格納できる配列を定義
    var chatDom =[];
    //文字列(この場合は引数のdom)を配列の要素として格納できる関数
    var p = function(dom){
        chatDom.push(dom);
    };

    //配列の要素として一つ一つ格納していき、最後にjoin関数で結合する
    //チャットの外側部分①
    p('<div id="bms_messages_container">');

        //ヘッダー部分②
        p('<div id="bms_chat_header">');
            p('<div id="bms_chat_user_status">');
                p('<div id="bms_status_icon">●</div>')
                p('<div id="bms_chat_user_name">ユーザー</div>');
            p('</div>');
        p('</div>');
              //タイムライン部分③
        p('<div id="bms_messages">');

            //メッセージ1(左側)
            p('<div class="bms_message bms_left">');
                p('<div class="bms_message_box">');
                    p('<div class="bms_message_content">');
                        p('<div class="bms_message_text">ほうほうこりゃー便利じゃないか</div>');
                    p('</div>');
                p('</div>');
            p('</div>');
            p('<div class="bms_clear"></div>');
        p('</div>');

        p('<div id="PushMore">');
        p('</div>');

        // テキストボックス、送信ボタン④
        p('<div id="bms_send">');
            p('<textarea id="bms_send_message"></textarea>');
            p('<div id="bms_send_btn">送信</div>');
        p('</div>');

        //jQueryのappend関数を使って、your_containerの直下にhtml要素を書き加える
        $('#your_container').append(chatDom.join(''));

        $.ajax({url:'json',datatype'json'})
        .done(function(data){
          $(data).each(function(){
            jdatatmp[num] = data;
            num=num+1;
          });
        mainBot(jdatatmp);
        });
});

function mainBot(jdata){
  for(var i = 0,i<=jdata.length-1,i++){
    dataTypeCheck(jdata[i]);
  }
}

function dataTypeCheck(jdata){
    switch(jdata.type){
      case "text":
        $('#PushMore').append('<div class="bms_message bms_left"><div class="bms_message_box">
                               <div class="bms_message_content"><div class="bms_message_text">'+jdata.value);
        $('#PushMore').append('<div class="bms_clear">')
        break;

      case "choice":
        ボタンを表示する処理
           var str=[];
           for(var i = 0 ;i<jdata.value.length;i=i+1){
               str[i]= '<div class="bms_message_btn" onclick="ButtonClickedMove(\''+jdata.value[i]+'\');>' + jdata.value[i] + '</div>';
           }
           var a="";
           for(var i = 0 ;i<str.length;i++){
              a = a + str[i];
           }

           $("#PushMore").append('<div class="bms_message bms_left"><div class="bms_message_box"><div class="bms_message_content"><div class="bms_message_text">' + jdata.text + '<br>' + a);
           $("#PushMore").append('<div class="bms_clear">');
           break;
    }
}

function ButtonClickedMove(i){

    console.log("gt"+i);
    var text=[];
    text=textChoice(i);

    for(var i = 0 ;i<text.length;i++){
        //左側 回答要素
        $("#PushMore").append('<div class="bms_message bms_left"><div class="bms_message_box"><div class="bms_message_content"><div class="bms_message_text">' + text[i]);
    }

    $("#PushMore").append('<div class="bms_clear">');


    if(i==0){
        return
    }
}

取り出したJsonオブジェクトのtypeがtextの場合、プログラムはValueの値をそのまま表示します。しかしchoiceだった場合は、Valueの値をButtonClickedMoveファンクションでボタン化し、表示します。

この時、今のままではJsonから取り出したすべての処理を一気にやってしまいます。typeがtextの場合はそれでもいいのですが、choiceの場合は一時停止し、ユーザーがボタンを押してから改めて次の配列を処理したいです。色々と調べて非同期通信やSleep機能での一時停止などは見つかりましたが、今回の場合はどうも使えそうにありません。

この場合、どんな技術をどのように使えば望む結果が出せるでしょうか? 

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 1

checkベストアンサー

0

こういうことですかね?

<script>
var json=[
  {"id":"1", "type":"text",},
  {"id":"2", "type":"choice",},
  {"id":"3", "type":"text",},
  {"id":"4", "type":"text",},
  {"id":"5", "type":"choice",},
  {"id":"6", "type":"choice",},
  {"id":"7", "type":"choice",},
  {"id":"8", "type":"text",},
  {"id":"9", "type":"text",},
  ];
$(function(){
  $('#continue').on('click',function(){
    $(this).hide();
  });
  (async()=>{
    for(var x of json){
      console.log(x);
      $('#continue').toggle(x.type=="choice")
      await new Promise(resolve=>{
        /* var c=0;//ゴミでした */
        var timerId=setInterval(()=>{ //timerIdはグローバルでなくても良かったので調整
          if($('#continue').is(':hidden')){
            clearInterval(timerId);
            resolve();
          }
        },100);
      });
    }
  })();
});
</script>
<input type="button" value="continue" id="continue">

流れの解説

  • async処理を宣言
  • jsonからデータをxとして取り出す
  • xを表示
  • #continueボタンをxのtypeがchoiceだったとき表示する、そうでないときは非表示
  • awaitでpromiseを呼び出し
  • promise内部では1/10秒ごとに#continueボタンの表示状態をチェック
  • 表示時=ユーザーからの入力待ち=promiseが進行しないので同期する
  • 非表示時=インターバル処理をとめ(clearInterval),promiseから復帰(resolve)
  • promiseから戻るとforループが進行しjsonの次のデータをチェック

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2019/09/11 21:15 編集

    遅くなってすいません。試してみましたが、確かにこれでできそうです。ありがとうございました。

    ところでもう少し質問をしたいのですが、いいでしょうか?
    このプログラムの動作は、
    「async() 以降の処理を起動時に行い、xのタイプがchoiceだった場合にのみcontinueボタンを表示し、ボタンが非表示だった場合はループを停止する。ボタンがクリックされるとボタンを非表示にし、async()以降の処理に続ける」
    という理解でよいですか?
    また、resolve();はどのように働いているのですか?

    よろしくお願いします。

    キャンセル

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

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