見出し画像

【2021.10.24】 GASのWebアプリでスプレッドシートの表を動的に表示する方法!

こんにちは!かれんです!

画像2

ログインした後に、その人の情報をスプレッドシート⬇︎からとって表示させたい!

画像1

と思ったので今回は、「GASのWebアプリでスプレッドシートの表を動的に表示する方法」についてです。

(これできるようになるまで、、鬼時間かかった、、)

(少しでも進めばいいと思ってるけど、、少しずつすぎ!!怒)

うん、

気を取り直して、結論からいうと、

スプレッドシートの情報をいれた配列をindex.htmlに渡す

です!

いきまうす。

(現時点でのコード最後に全部載せます!)

1. スプレッドシートの情報を配列にいれる

コード.gsに⬇︎追加

/** 
* doPostへシフトの時間が入った配列を返す
* 
* @return 日にちと時間が入った配列
*/
function receiveShift(name_row){
 const sheets = SpreadsheetApp.openById('①');  //スプレッドシートをとってくる
 const sheet = sheets.getSheetByName("シート1");  //シートをとってくる

 const dates = sheet.getRange(1,3,1,16).getValues();  //日にち
 const times = sheet.getRange(name_row,3,1,16).getValues();  //時間

 let date;  //日にち
 let start_time;  //スタート時間
 let end_time;  //終わりの時間
 let shift_dates = [];  //全てを格納した配列
 let shift_dates_index = 0;
 for(let i = 0; i<dates[0].length; i=i+2){
   date = Utilities.formatDate( dates[0][i], 'Asia/Tokyo', 'dd日');

   if(times[0][i] != "" && times[0][i+1] != ""){  //時間が入ってないときエラーが起きるので、入ってる時だけ格納する、空欄なら空で格納
     start_time = Utilities.formatDate( times[0][i], 'Asia/Tokyo', 'HH:mm');
     end_time = Utilities.formatDate( times[0][i+1], 'Asia/Tokyo', 'HH:mm');
   }else{
     start_time = "";
     end_time = "";
   }

   shift_dates[shift_dates_index] = [date,start_time,end_time];
   shift_dates_index++;
 }

 return shift_dates;
}

①スプレッドシートのid

2. 配列をindex.htmlに送る

doPost()内を変更⬇︎

template = HtmlService.createTemplateFromFile('index');
   template.name = name; //名前を送る
   template.shift_dates = receiveShift(judges[1]); //シフトの時間を送る(judges[1]にはその人が何行かが入っている)

   return template
     .evaluate()
     .setTitle("最初の画面")
     .addMetaTag('viewport', 'width=device-width, initial-scale=1');

変数nameと、配列shift_datesをindex.htmlに送っている

3.  表を埋め込む

index.htmlのbody内に⬇︎追加

<div class=index-div>
     <h1><?=name?>さんが提出したシフト</h1>
     <table id="shift_tbl">
       <tr>
         <? for(let i = 0; i < shift_dates.length; i++){ ?>
           <th colspan="2"><?= shift_dates[i][0] ?></th>
         <? } ?>
       </tr>
       <tr>
         <? for(let i = 0; i < shift_dates.length; i++){ ?>
           <th><?= shift_dates[i][1] ?></th><th><?= shift_dates[i][2] ?></th>
         <? } ?>
       </tr>
     </table>
   </div>

4. デプロイをテストしてみる

画像3

うん、まだデザインしてないからあれやけど、、w

できた〜!!

まとめ

最後まで読んでいただき本当にありがとうございます!

今回は、「GASのWebアプリでスプレッドシートの表を動的に表示する方法」についてお伝えしました。

このようにできるようになったのは、、⬇︎のおかげです、、

(分かりやすかった、、、大感謝です、、)

じゃまたね〜♡

※現時点での実装されてる機能と全てのコード

現時点での機能こんな感じ⬇︎

・おしゃれなログイン画面

・ログイン後にその人の名前を反映させる

・スマホでいい感じに表示させる

・スプレッドシートの表を反映させる

現時点でのファイルこんな感じ⬇︎

画像4

・コード.gs

function doGet() {
 const htmlOutput = HtmlService.createTemplateFromFile("login");

 return htmlOutput
   .evaluate()
   .setTitle("ログイン画面")
   .addMetaTag('viewport', 'width=device-width, initial-scale=1');
}

function doPost(postdata){
 const name = postdata.parameters.name.toString();  //ログイン時の名前
 const password = postdata.parameters.password.toString();  //ログイン時のパスワード
 const judges = judgeAccounts(name, password);  //あっていたらtrue、間違っていたらfalseが返ってくる

 let template;//次に遷移する画面
 if(judges[0]==1) {  //judge[0]がtrue(1)ならindex.htmlに送る
   template = HtmlService.createTemplateFromFile('index');
   template.name = name; //名前を送る
   template.shift_dates = receiveShift(judges[1]); //シフトの時間を送る(judges[1]にはその人が何行かが入っている)

   return template
     .evaluate()
     .setTitle("最初の画面")
     .addMetaTag('viewport', 'width=device-width, initial-scale=1');
 } else {  //judge[0]がfalse(0)ならerror.htmlに送る
   template = HtmlService.createTemplateFromFile('error');

   return template
     .evaluate()
     .setTitle("エラー")
     .addMetaTag('viewport', 'width=device-width, initial-scale=1');
 }
}

/** 
* doPostへnameとpassがあっているかを返す
* 
* @return true or falseを返す
*/
function judgeAccounts(name, password){
 const sheets = SpreadsheetApp.openById('①');  //スプレッドシートをとってくる

 const sheet = sheets.getSheetByName("②");  //シートをとってくる

 const accounts_name = sheet.getRange(③).getValues();  //名前とってくる
 const accounts_pass = sheet.getRange(④).getValues();  //パスワードとってくる
 
 let judge = 0;
 let name_row  = 0;
 for(let i = 0; i < accounts_name.length; i++){  //名前とパスワードがあっていればtrue、あってなければfalseを返す
   if(accounts_name[i] == name && accounts_pass[i] == password){
     judge = 1;
     name_row = i+2;
     break;
   }
 }
 const judges =[judge,name_row];
 return judges;
}

/** 
* doPostへシフトの時間が入った配列を返す
* 
* @return 日にちと時間が入った配列
*/
function receiveShift(name_row){
 const sheets = SpreadsheetApp.openById('①');  //スプレッドシートをとってくる
 const sheet = sheets.getSheetByName("②");  //シートをとってくる

 const dates = sheet.getRange(1,3,1,16).getValues();  //日にち
 const times = sheet.getRange(name_row,3,1,16).getValues();  //時間

 let date;  //日にち
 let start_time;  //スタート時間
 let end_time;  //終わりの時間
 let shift_dates = [];  //全てを格納した配列
 let shift_dates_index = 0;
 for(let i = 0; i<dates[0].length; i=i+2){
   date = Utilities.formatDate( dates[0][i], 'Asia/Tokyo', 'dd日');

   if(times[0][i] != "" && times[0][i+1] != ""){  //時間が入ってないときエラーが起きるので、入ってる時だけ格納する、空欄なら空で格納
     start_time = Utilities.formatDate( times[0][i], 'Asia/Tokyo', 'HH:mm');
     end_time = Utilities.formatDate( times[0][i+1], 'Asia/Tokyo', 'HH:mm');
   }else{
     start_time = "";
     end_time = "";
   }

   shift_dates[shift_dates_index] = [date,start_time,end_time];
   shift_dates_index++;
 }

 return shift_dates;
}

①スプレッドシートのid

②シート名

③名前が入ってる列の範囲

④パスワードが入ってる列の範囲

・login.html

<!DOCTYPE html>
<html>
<head>
  <base target="_top">
  <?!= HtmlService.createHtmlOutputFromFile('css').getContent(); ?>
  <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
  <div class="form-wrapper">
    <h1>ログイン</h1>
    <form method="post" action="①">
      <div class="form-item">
        <label for="name"></label>
        <input type="name" name="name" required="required" placeholder="名前"></input>
      </div>
      <div class="form-item">
        <label for="password"></label>
        <input type="password" name="password" required="required" placeholder="パスワード"></input>
      </div>
      <div class="button-panel">
        <input type="submit" class="button" title="Login" value="Login"></input>
      </div>
    </form>
  </div>
</body>
</html>

①デプロイしたURL

・error.html

<!DOCTYPE html>
<html>
<head>
  <base target="_top">
  <?!= HtmlService.createHtmlOutputFromFile('css').getContent(); ?>
  <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
  <h2>アクセス権限のないユーザーです</h2>
</body>
</html>

・index.html

<!DOCTYPE html>
<html>
 <head>
   <base target="_top">
   <?!= HtmlService.createHtmlOutputFromFile('css').getContent(); ?>
   <meta name="viewport" content="width=device-width, initial-scale=1">
 </head>
 <body>
   <div class=index-div>
     <h1>Hello World</h1>
     <h2><?=name?>さん、こんにちは!</h2>
   </div>
   <div class=index-div>
     <h1><?=name?>さんが提出したシフト</h1>
     <table id="shift_tbl">
       <tr>
         <? for(let i = 0; i < shift_dates.length; i++){ ?>
           <th colspan="2"><?= shift_dates[i][0] ?></th>
         <? } ?>
       </tr>
       <tr>
         <? for(let i = 0; i < shift_dates.length; i++){ ?>
           <th><?= shift_dates[i][1] ?></th><th><?= shift_dates[i][2] ?></th>
         <? } ?>
       </tr>
     </table>
   </div>
 </body>
</html>

・css.html

<style type="text/css">
/* Fonts */
@import url(https://fonts.googleapis.com/css?family=Open+Sans:400);  //英数字のフォント
//日本語のフォントはsans-serifで統一(もともと用意されてる)

/* Simple Reset */
* { margin: 0; padding: 0; box-sizing: border-box; }

/* body */
body {
 background: #e9e9e9;
 color: #5e5e5e;
 font: 400 87.5%/1.5em sans-serif;
}

/* エラー画面レイアウト */
h2 {
 text-align: center;
 padding: 1em 0;
}

/* Form Layout */
.form-wrapper {
 background: #fafafa;
 margin: 3em auto;
 padding: 3em 1em;
 max-width: 370px;
}

h1 {
 text-align: center;
 padding: 1em 0;
}

form {
 padding: 0 1.5em;
}

.form-item {
 margin-bottom: 0.75em;
 width: 100%;
}

.form-item input {
 background: #fafafa;
 border: none;
 border-bottom: 2px solid #e9e9e9;
 color: #666;
 font-family: sans-serif;
 font-size: 1em;
 height: 50px;
 transition: border-color 0.3s;
 width: 100%;
}

.form-item input:focus {
 border-bottom: 2px solid #c0c0c0;
 outline: none;
}

.button-panel {
 margin: 2em 0 0;
 width: 100%;
}

.button-panel .button {
 background: #f16272;
 border: none;
 color: #fff;
 cursor: pointer;
 height: 50px;
 font-family: 'Open sans', sans-serif;
 font-size: 1.2em;
 letter-spacing: 0.05em;
 text-align: center;
 text-transform: uppercase;
 transition: background 0.3s ease-in-out;
 width: 100%;
}

.button:hover {
 background: #ee3e52;
}

/* index画面レイアウト */
.index-div {
 background: #fafafa;
 margin: 3em auto;
 padding: 3em 1em;
 max-width: 370px;
}
</style>


いいなと思ったら応援しよう!