HTMLでオンラインテストを作ってみた話②

javascriptから別のjavascriptを呼び出してみる

オンラインテストの出題部分の作成を続けます。



前回で問題の表示→解答のサイクルはできたので、次に手がけるのは問題のデータを分けたファイルの作成です。
問題だけ別ファイルにできれば、あとで問題数を増やすときに楽ですからね。

ということで必要になるのは、「javascriptから別のjavascriptを呼ぶ」という処理になります。
ググってみるといろいろな方法が出てきましたが、実際に動かしてみて一番しっくりきたのがこのページで出てきた「jQueryのAjax」でした。

って、未だにそれが何を意味してる言葉なのかわかってませんが。

jQueryって何?

よくわかりませんが、どうやらjQueryってのはjavascriptのプラグイン的なもののようで。
こいつがあると追加コマンドが使用できる的な。
で、html内でgoogleから読み込んでおくと使えるらしいことがわかりました。

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>

こんなの書いとけば勝手に読み込んでくれるみたいです。
で、jQueryを導入したら、次にそいつのコマンドです。
どうやら$から始まるみたいで、あとはさっきのサイトにあったものを元に。

    $.ajax({
      type : 'GET',
      url: './js/Testdata.js',
      dataType: 'script',
      success: function(data) {
        Qdatacall();
      }
    });

前回作ったquestioncontrol.jsの関数next()内で、こんな感じで実行してみます。
Testdata.jsという別ファイルを作って、そこで関数Qdatacallを実施して、問題データの呼び出しをします。

で、関数next()内で、問題の番号を乱数で指定、その番号によってQdatacall内で問題を出力、という流れです。
で、できたのがこんな感じです。
前回とHTML、CSSに変更はありません。

See the Pen MdBPWG by Haru-You (@HaruYou) on CodePen.


見てわかる?ように、問題データは格納されていません。
haruyou-blog.com/NP/1/jsから拾ってきてくれています。

ただ、コンソールを見てると実行時に「XML パースエラー: 構文エラーです。」って表示されてるのが気になります。
けど、動いてるからいいや。

javascriptでCSVのデータを読み込む

とはいえ、javascriptじゃ問題の編集に手間がかかってしょうがありません。
次に目指すのは、問題文のデータをスプレッドシートで編集できるCSV化することです。

javascriptで配列を読み込ませて、セルごとに区切って問題文と解答を拾えるかな?というイメージです。

ひとまずググってみると、またもやAjaxを利用してできるようです。
ありがとうAjax。
アジャクスなのかエイジャックスなのか、野上彰と飯塚高史のタッグなのか知らないけど。


ということで、こんな感じにquestioncontrolの中に組み込みます。
必要なときだけ関数csv();で呼びだすイメージですね。

function csvToArray(path) {
  var csvData = new Array();
  data = new XMLHttpRequest();        
  data.open("GET", path, false);//ここをtrueにすると読み込みが間に合わない  
  data.send(null);
  var LF = String.fromCharCode(10);
  var lines = data.responseText.split(LF);
  for (var i = 0; i < lines.length;++i) {
          var cells = lines[i].split(",");
          if( cells.length != 1 ) {
                  csvData.push(cells);
          }
  }
  return csvData;
}

function csv(){
  DataCSV = csvToArray("https://haruyou-blog.com/NP/1/js/QuestionDATA.csv");
}

で、ここの4行目のdata.openのところで3番目の引数にtrueを指定すると非同期読み込み、falseにすると同期読み込みってことで、同期読み込みにすると読み込み終了までフリーズしちゃうみたいです。
しかし、trueにすると読み込みが間に合わないのか、csvのデータが来ません。
どっかで先に読んどく仕組みが必要ですかね。
とりあえずfalseにしても動作に支障はないので、このまま進めます。

次に必要になるのが問題番号によって必要な配列だけを拾う処理です。
QuestionDATA.csvの1列目に問題番号を入力して、これにフィルターすればよさそうです。
で、CSVのフィルターについてググったらでてきたのがこんな感じのコード。

function CSVArray(p){
    CSVCell = _.filter( DataCSV, function(get) {
    var r = _.filter( get, function( number ) {
    return number === p;
    } );
    return r.length > 0;
    } );
}

underscoreって何?

なんか、またもや見たことない記号から始まるコマンドです。
調べてみると、underscoreって代物のようで。
Jqueryと同じように使えばいいっぽいです。

<script type="text/javascript" src="https://underscorejs.org/underscore-min.js"></script>

だもんで、HTMLでこいつを読み込み。
理由はわかりませんが、このコマンドでcsvから取り出した配列を問題番号でフィルターできてます。

最後に、フィルターして取り出した中から、さらに問題をとりだします。
2列目に問題、3列目に解答を入力してあるので、これをそれぞれ変数に代入します。

        case 3://csv問題 社会科
        q_title="鎌倉時代";
        CSVArray(3);
        a=Math.floor(Math.random()*CSVCell.length);
        question=CSVCell[a][1];
        answer=CSVCell[a][2];
        break;

問題番号3に設定された問題の数だけaに乱数振って、その中から一問出題されるイメージです。
で、こんな感じになりました。

ソースを見てもTestdataとQuestionDATAが入っていませんが、確かにデータを読んでくれてます。

この状態でのTestdata.jsはこんな感じ。

function Qdatacall(){
    //問題switch
    switch(QID){
        case 1://1けたのたし算
        c= 9;
        while (c <=9){
            a =(Math.floor( Math.random() * 9)+1);
            b =(Math.floor( Math.random() * 9)+1);
            c = a + b;
        }//計算ループ
        q_title="くりあがりの たしざん";
        question = a+"+"+b+"=";
        answer=c;
        break;
        
        case 2://1けたの引き算
        c= 10;
        while (c >=10){
            a =(Math.floor( Math.random() * 9)+10);
            b =(Math.floor( Math.random() * 9)+1);
            c=a-b;
        } //計算ループ
        q_title="くりさがりの ひきざん";
        question =a+"-"+b+"=";
        answer=c;
        break;

        case 3://csv問題 社会科
        q_title="鎌倉時代";
        CSVArray("3");
        a=Math.floor(Math.random()*CSVCell.length);
        question=CSVCell[a][1];
        answer=CSVCell[a][2];
        break;

        case 4://csv問題 ???
        q_title="なんかよくわからない問題";
        CSVArray("4");
        a=Math.floor(Math.random()*CSVCell.length);
        question=CSVCell[a][1];
        answer=CSVCell[a][2];
        break;
    
    
}// switchの終わり
    
    document.getElementById("q_title").innerHTML=q_title;
    document.getElementById("text_question").innerHTML=question;
}

function CSVArray(p){
    CSVCell = _.filter( DataCSV, function( get ) {
    var r = _.filter( get, function( number ) {
    return number === p;
    } );
    return r.length > 0;
    } );
}

でもって、csvファイルの内容がこんな感じです。

QID,問題,解答
3,源頼朝が守護・地頭の任命権を得たのは何年のことか答えなさい,1185
3,源頼朝の妻で、のちに「尼将軍」と呼ばれた人物の名を答えなさい,北条政子
3,鎌倉幕府第2代将軍の名前を答えなさい,源頼家
4,木村健吾といえば?,稲妻レッグラリアート
4,愛ってなんだ?,ためらわないことさ
4,西武ライオンズ史上最高の外国人選手は?,スティーブ・オンティベロス

4-1は「トライアングル・スコーピオン」でも正解ですし、4-2は「躊躇わないことさ」と漢字で書かれた場合どうするか。
4-3は「テリー・ウィットフィールド」「郭泰源」も別解として適用したい。デストラーデは×です。
なんてことを考えると、別解の枠をCSVに入れ、判定システムでも入力したinputansが解答および別解の配列内に含まれるかどうかの判定にする必要がありそうです。
まあ、それくらいならなんとかなりそうなんで後回し。


今回はランダムで問題番号(QID)を振りましたが、これを自由に選べるようにするのが次の作業ということになります。
なので、次回は「教科・単元を選択するシステム」を作ることにします。

出題画面と判定部分の改良

前の段落で別解について考えましたが、あれこれと改良・機能追加したい点が見えてきます。

  1. 解答の全角/半角
  2. 4択型の出題
  3. 複数解答を必要とする問題(分数とか)
  4. 問題内での画像の表示

この辺はまあ解決済みなのですが、こういった小ネタをどうやって解決していったかは、大筋が終わってから書きます。
いつの日かわかりませんが。
そんなん書く暇あったら問題作るほうが先なんでしょうけどね。

新着記事

都立一貫校作文問題集

都立中高一貫校のHPで公開されている適性検査問題の作文(適性検査Ⅰ)を1つのPD ...

日本の歴史の歌

社会科、日本の歴史の各時代の重要事項を「アルプス一万尺」に乗せて歌います。。

中学受験理科講座 植物のつくりとはたらき(3)〜光合成・呼吸・蒸散〜

理科の生物範囲、植物のつくりとはたらきについて、光合成・呼吸・蒸散のはたらきにつ ...

月の満ち欠けの歌

中学受験で頻出の11種類の水溶液の名前、液性、指示薬の変化、主な水溶液の識別ポイ ...

緊急事態宣言下での塾と中学受験

コロナウイルスの影響で、中学受験の学習塾業界にも営業自粛要請が出ています。この状 ...