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 更新:フォルダ名やファイル名を変更)
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> <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>
以上、