ASCASO社のエスプレッソマシンについてマニュアル和訳を勝手に進めています

tomatojuicer222's diary

ASCASO社のエスプレッソマシンについてマニュアル和訳を勝手に進めています→ http://tomatojuicer222.hatenablog.com/entry/2014/11/19/121242

google apps scriptで簡単なwebアプリを作ってみた

googlespreadsheet(つまりいわゆるエクセル的な)にデータベース様のテーブルを作っておき、このシートを開けないスマホやマック環境でも、HTMLフォームから更新できるようにする。

 

tomatojuicer222.hatenablog.com

 

・おおざっぱな流れは以下。
シート上にテーブルのひな形を作成する。
ここではレコードが増えた場合も表示をスムーズにするため、入力規則やセル内の計算式を使用しない。つまり手動ならなんでも書けてしまう様なシートを作っておく。
代わりにHTMLのフォーム側で値チェック等を行い、検索に差し支えるような誤入力を抑止する設計とする。

サーバー側のjavascript処理をコーディング/フォーム側のHTML(CSS,javascript含む)で画面作成し、大枠が完成したらプロジェクトをWEB上に公開する。
公開したURLにアクセスすると、サーバー上ではdoGet()メソッドが呼ばれる。
このdoGet()メソッドに、作成したHTMLで描画するコードをHTMLserviceクラスを使って書いておく。
HTMLからの応答方法としては、html側でinput type="button"のonClickに、google.script.runすればよい。

ここまではググればすぐでてくるので詳細は割愛。

・以降あんまりググっても書いてなかった、どハマりした点メモ。

・引数に設定できる値が限られているので注意。
google.script.runで呼び出す際の引数は種類が限られている。基本はまぁformを渡すんだけど、この場合HTMLのformオブジェクトがそのまま渡るわけではなく、formの各要素の値がneme:valueのマップ形式で通知されてるっぽい。
そのためbuttonなど(一般的なsubmitボタンで渡る)一部の項目についてはvalueがとれないので要注意。
たとえば押したボタンによって参照するデータを区別する、みたいなことをする場合、次に書く通りブラウザ側で処理してから渡さないとダメ。

複数formの取扱い/input要素の取扱い。
複数フォームを用意して、押したボタンによってどちらかのフォームか判定、送信用の抽象フォームに移し替える、みたいな処理。
ググると結構でてくるからメジャーなやり方なんだろうけど、onclick処理に入った時点で各formの値にアクセスする方法は結構嘘ばっかり。まともに通るサンプルソースに出会えなかった。
具体的にはサンプルの「document.formhidden」の時点では認識できてるんだけど、その先の.nameからはブラウザによって動いたり動かなかったり。

<!--うまく動かないダメな例です!!!-->
    <!--送信に使う抽象フォーム-->
    <form name="formhidden">
         <input type="hidden" name="radio" value="">
         <input type="hidden" name="rank" value="">
    </form>
    <!--記入用フォーム1-->
    <form name="forminput1">
         <input type="radio" name="r1" value="1">
         <input type="text" name="rank1" >
         <input type="button" name="b1" onclick="sendForm1(this.parentNode)">
    </form>
    <!-記入用フォーム2-->
    <form name="forminput2">
         <input type="radio" name="r2" value="2">
         <input type="text" name="rank2" >
         <input type="button" name="b2" onclick="sendForm2(this.parentNode)">
    </form>

    <script>
        function sendForm1(form){ //フォーム1からの送信
         document.formhidden.radio = form.r1;
         sendForm(document.formhidden);
        }

        function sendForm2(form){ //フォーム2からの送信
         document.formhidden.radio = form.r2;
         sendForm(document.formhidden);
        }

        sendForm(form){
         //サーバーに送信
         google.script.run.send(form);
        }
    </script>
<!--うまく動かないダメな例ここまで-->

これをまともに動かすは、idとnameの違いをきちんと理解する必要がある。

  • id:全要素で重複があってはいけない
  • name:inputのtype="radio"に代表されるように、重複がある前提

つまりnameは受け取ったサーバー側でvalueを取るためのものであり、本来要素の特定に使うものではない!
「document.name」で値をとってくること自体が(十分に注意して設計した場合に)一部ブラウザのみで使えるおまけ機能であって、基本的にNGと思っとけばよさそう?
個別に特定可能な要素には全てidを振っておき「document.getElementById("id")」で取得する。
ラジオボタンみたいなnameまでしか特定できないものは「document.getElementsByName("name")」で一度同じnameグループの要素リストを取得する。
このリストには配列の添え字でアクセス可能なので、具体的には以下の例のようにやれば選択した(checkedな)値をとることができる。

    var i;
    var selectedval;
    var elements = document.getElementsByName("name");
    for (i=0; i<elements.length; i++){
     if(elements[i].checked){
      selectedval = elements[i].value;
     }
    }

このへんをちゃんとやらずに.nameでアクセスしようとすると、
1.配列の先頭が取れる
2.undefinedな値でエラーになる(これがHTML標準なのかな?)
3.選択したラジオボタンのvalueがとれる(一部ブラウザのみのおまけ機能、一見ただしく動いて見える)
あたりが環境によってまちまちに動く。このへんが冒頭の不具合の原因。

同じ理屈はselectにもいえて、やっぱりID指定や.nameでselect要素自体を指定しても、配下option要素のvalueはとれない。
ここもselect要素をidで取得したら、「.options」プロパティで配下optionリストを取得する。
このリストには配列の添え字でアクセス可能かはよくわからん。ちょっと複雑だが以下。
何番目のoptionが選択されたかという情報を「.selectedIndex」プロパティで取得し、
options側で持ってるアクセサメソッド「.item()」にこのselectedIndexを指定する。
これで選択した(selectedな)option要素の値をとることができる。

    var select = document.getElementById("selectid");
    var options = document.getElementById("selectid").options;
    var selectedvalue = options.item(select.selectedIndex).value;

・spreadSheetAppのスプレッドシート特定方法
スプレッドシートを操作する方法はググればでてくるので割愛。
ただしwebアプリ的に使う場合、シートと連携しているGASであってもactivecheetではとれない。
openByIdみたいなメソッドを使って明示的に開く必要がある。
ここでいうIDはシートのURLのうち、aaa/d/XXXXXX/aaa のXXXXXX部分。
とりあえずグローバル変数に固定値で保持しておく。
動的に指定のシートを取れるよなうまい取り方がないものか模索中。(公開することを想定して)


・その他
この辺のうまくいかなかった点は、ググってもわからなかった項目で、何度も試行を繰り返すなかでなんとか解決してきた。
そんなことをやってたら「一秒当たりのスクリプト実行回数が多すぎます」みたいなエラーがでたよ。
おそらくこの24時間で500~1000くらいの回数実行してるから、その辺のどっかに実行回数の制限ポイントがあるんだろうな。ググっても出てこなかったけど。