マイブーム@技術と生活

仕事や生活に関わる技術的なことを記述します。

テンプレート自分用 (JavaScript)

HTML、JavaScriptデバッグは、Google Chrome で開いて、右上ボタン、その他のツール、デベロッパー ツール、を使います (Console を表示)


(2022/01/28 19:20 更新: Show_CustomControl.html の class の宣言を、別ファイル (js) に分離)
(2022/01/28 23:00 更新: init(str, sub) に変更。load() から呼び出し。初期値を、DB を読み込んだ後など、に書ける)
(2022/02/04 18:45 更新:サーバー側のアドレスを拡張子なしに変更。RewriteRule を使う)
(2022/02/16 10:45 更新:フォルダ名やファイル名を変更)



f:id:sato7411:20220128100816p:plain:w300


f:id:sato7411:20220128100831p:plain:w300



Show_CustomControl.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset='utf-8' />
    <title>JavaScript Promise, resolve and then Sample</title>
    <script>

      // var resource = { // debug
      //   "category": "プログラマ",
      //   "subcategory": "COBOL"
      // };


      function makeRequest() {

        //
        // Get Parent Select
        //
        var select = document.getElementById('category');
        var idx = select.selectedIndex;
        var str = select.options[idx].value;
        //
        //

        chbcapi.request({
          'path': 'https://kamimatsu-db.com/Api/CustomControl/ChangeChild',
          'method': 'POST',
          'body': JSON.stringify( {'category': str} ) // JSON.stringify(resource)
        }).then(function(resp) {
          writeResponse(resp.result);
        });
      }

      
      function initChild(str, sub) {

        //
        // Initial Value
        //
        var select = document.getElementById('category');
        for (var i=0; i<select.options.length; i++) {
          if (select.options[i].value == str) {
            break;
          }
        }
        select.selectedIndex = i;
        //
        //

        chbcapi.request({
          'path': 'https://kamimatsu-db.com/Api/CustomControl/ChangeChild',
          'method': 'POST',
          'body': JSON.stringify( {'category': str, 'subcategory': sub} ) // JSON.stringify(resource)
        }).then(function(resp) {
          writeResponse(resp.result);
        });
      }


      function writeResponse(response) {
        console.log(response);

        //
        // Change Child Select
        //
        var select = document.getElementById('subcategory');
        while(select.firstChild) {
          select.removeChild(select.firstChild); 
        }
        for (const elem of response) {
          var option = document.createElement('option');
          option.value = elem.value;
          option.text = elem.text;
          if (elem.selected) {
            option.selected = true;
          }
          select.appendChild(option);        
        }
        if (response.length > 0) {
          select.disabled = false;
        } else {
          select.disabled = true;
          var option = document.createElement('option');
          option.value = " ";
          option.text = " ";
          option.selected = true;
          select.appendChild(option);        
        }
        //
        //
      }

    </script>
    <script async defer src="https://kamimatsu-db.com/Api/Js/ChbcApi.js">
    </script>
  </head>


  <body>
    <!-- <button id="rest" onclick="makeRequest();">Make Request</button>
    <div id="info"></div> debug -->
    <select id="category" name="category" size="1" onchange="makeRequest();" style="width: 170px;">
      <option value="選んで下さい">選んで下さい</option>
      <option value="先生">先生</option>
      <option value="プログラマ">プログラマ</option>
      <option value="デザイナー">デザイナー</option>
      <option value="マッサージ">マッサージ</option>
      <option value="カウンセル">カウンセル</option>
      <option value="その他">その他(コメントへ記入)</option>
    </select>&nbsp;&nbsp;
    <select id="subcategory" name='subcategory' size="1" style='width:170px;' disabled>
      <option value=" "> </option>
    </select><br>
    <script>
      function load() {
        initChild('プログラマ', 'COBOL');
      }
      window.onload=load;
    </script>
  </body>
</html>

 
 
ChbcApi.js

class ChbcApi {
  request(data) {
    console.log(data);
    return new Promise(function(resolve) {

      fetch(data.path, data)
        .then(function(res) {
          return( res.json() );
        })
        .then(function(json) {
          console.log(json);
          if ( Array.isArray(json) ) {
            var resp = { result: json };
          } else {
            var resp = { result: JSON.parse(json) };
          }
          resolve(resp);
        });

    });          
  }
}
const chbcapi = new ChbcApi();

 
 
 
サーバーにアップロードする PHP ファイルです。POST 経由で、JSON のパラメータを受け取って、JSON で結果を返します

アドレス https://kamimatsu-db.com/Api/CustomControl/ChangeChild
パラメータ POST 又はアドレス
リクエスト本文 JSON
応答 JSON


ChangeChild.php

<?php
header("Content-Type: application/json; charset=utf-8");
header("Access-Control-Allow-Origin: *");
$json = file_get_contents('php://input');
$data = json_decode($json, true);


//
// Change Child
//

function opt($str, $sel)
{
    return array( 'value' => $str, 'text' => $str, 'selected' => ($str == $sel) );
}

$res = array();
$sel = $data['subcategory'];
switch ($data['category']) {
    case '先生':
        $res[0] = opt("選んで下さい", $sel);
        $res[1] = opt("英語", $sel);
        $res[2] = opt("数学", $sel);
        $res[3] = opt("物理", $sel);
        $res[4] = opt("小学生", $sel);
        $res[5] = opt("パソコン", $sel);
        $res[6] = opt("その他(コメントへ記入)", $sel);
        break;

    case 'プログラマ':
        $res[0] = opt("選んで下さい", $sel);
        $res[1] = opt("C#", $sel);
        $res[2] = opt("VB.NET", $sel);
        $res[3] = opt("JAVA", $sel);
        $res[4] = opt("Objective-C", $sel);
        $res[5] = opt("C/C++", $sel);
        $res[6] = opt("COBOL", $sel);
        $res[7] = opt("Python", $sel);
        $res[8] = opt("その他(コメントへ記入)", $sel);
        break;

    case 'マッサージ':
        $res[0] = opt("選んで下さい", $sel);
        $res[1] = opt("指圧", $sel);
        $res[2] = opt("リラクゼーション", $sel);
        $res[3] = opt("タイ古式", $sel);
        $res[4] = opt("その他(コメントへ記入)", $sel);
        break;

    case 'カウンセル':
        $res[0] = opt("選んで下さい", $sel);
        $res[1] = opt("経営", $sel);
        $res[2] = opt("恋愛", $sel);
        $res[3] = opt("その他(コメントへ記入)", $sel);
        break;

    default:
        break;
}

// $res = ["選んで下さい", "経営", "恋愛", "その他(コメントへ記入)"]; // debug
// $res[0] = ['value'=>'選んで下さい', 'text'=>'選んで下さい', 'selected'=>false]; // debug
// $res[1] = ['value'=>'経営', 'text'=>'経営', 'selected'=>false]; // debug
// $res[2] = ['value'=>'恋愛', 'text'=>'恋愛', 'selected'=>true]; // debug
// $res[3] = ['value'=>'その他(コメントへ記入)', 'text'=>'その他(コメントへ記入)', 'selected'=>false]; // debug

//
//


echo(json_encode($res));
?>

 
 
 
JavaScript の Promise、resolve、then の動作を確認したプログラムです

「function(resolve) {」は「(resolve) => {」に置き換えれます。「.then(function(resp) {」も同様に「.then((resp) => {」。request の data は渡されますが使っていません。resolve の resp が戻されて .then(function の resp (異なる名前でも良い) に渡されます

処理が失敗した時に異なる処理をしたい場合は、「function(resolve, reject) {」または「(resolve, reject) => {」 を作って、reject で error を戻して、「.catch(function(error) {」または「.catch((error) => {」で処理します

JavaScript では 「resp = { result: { name: "Ronaldo", team: "Juventus"} }」は resp.result や response.name のようにアクセスできます (ここで response = resp.result)。resp はオブジェクトと呼ばれています。PHP の配列とは扱いが異なりますね

var と const はスコープにだけ注意して適当に使っています。PHP の場合だと外で作った変数が function の内側に渡されません (必要ならば function の内側で global 宣言する)

request やその内側の fetch はマルチスレッドで動作しています。makeRequest(); の直後に <div id="info"> の内容を見ても、結果は更新されていません。続きの処理が必要ならば writeResponse() の中に書かなければなりません (または、return new Promise を書く)

※ promise.then の呼び出しは promise を返す



test.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset='utf-8' />
    <title>JavaScript Promise, resolve and then Sample</title>
    <script>

      var resource = {
        "summary": "Appointment",
        "location": "Somewhere",
        "start": {
          "dateTime": "2022-01-16T10:00:00.000-07:00"
        },
        "end": {
          "dateTime": "2022-01-16T10:25:00.000-07:00"
        },
        "visibility": "public"
      };

      function makeRequest() {
        chbcapi.request({
          'path': '/calendar/v3/calendars/primary/events',
          'method': 'POST',
          'body': resource
        }).then(function(resp) {
          writeResponse(resp.result);
        });
      }

      function writeResponse(response) {
        console.log(response);
        var divinfo = document.getElementById('info');        
        divinfo.append('name: ' + response.name + ', team: ' + response.team);
      }

      class ChbcApi {
        request(data) {
          console.log(data);
          return new Promise(function(resolve) {
            const resp = { result: { name: "Ronaldo", team: "Juventus"} };
            resolve(resp);
          });
        }
      }
      const chbcapi = new ChbcApi();

</script>
  </head>
  <body>
    <button id="rest" onclick="makeRequest();">Make Request</button>
    <div id="info"></div>
  </body>
</html>

 
 
 
簡単な fetch の例です。return や resolve を書かなければ、値を返さず、処理のみ行います (2番目の then)。fetch のマニュアルはこちら


<script>
  fetch('https://ipinfo.io?callback')
    .then(function(res) {
      return( res.json() );
    })
    .then(function(json) { 
       console.log(json.ip);
       var addr = document.getElementById("addr");
       addr.innerHTML = json.ip;
    });
</script>
<span id="addr"></span><br>

 
 
 
Promise 有りと Promise 無しを比較した例です。Promise 無しは先に "by initChild" が表示されて、3秒後に "by setTimeout" が表示されます。Promise 有りは両方ほぼ同時に表示されます


<!DOCTYPE html>
<html>
  <head>
    <meta charset='utf-8' />
    <title>JavaScript Promise, resolve and then Sample</title>
    <script>

      function makeRequest() {
        return new Promise(function(resolve) { // Promise 無し時はこの行をコメントアウト

          setTimeout(function() {
            console.log("by setTimeout");
            var divinfo = document.getElementById('info');
            divinfo.append("by setTimeout");
            resolve(); // Promise 無し時はこの行をコメントアウト
          }, 3000);

        }); // Promise 無し時はこの行をコメントアウト
      }

      function initChild() {
        console.log("by initChild");
        var divdata = document.getElementById('data');
        divdata.append("by initChild");
      }

      function load() {

        // Promise 有り
        makeRequest()
        .then(function() {
          initChild();
        });

        // Promise 無し
        // makeRequest();
        // initChild();

      }
      window.onload=load;
    </script>
  </head>
  <body>
    <div id="info"></div>
    <div id="data"></div>
  </body>
</html>

 
 
 
以上、