このブログはプログラム開発や学習などの際に役立つ知識や情報を発信するエンジニアのためのトータル技術ブログです。
ご意見やご要望にも積極的に答えていきますので、お気軽にお問い合わせください。

記事へのリクエストはこちら

③ JavaScript で表計算アプリを作ってみる

HTML/CSS
スポンサーリンク

こんにちは!あっきーです!

前回、前々回と合計2回にわたって JavaScript の DOM 機能を使った表計算アプリを一緒に作りましたね!

⬇︎⬇︎前回、前々回の記事の参照はこちら⬇︎⬇︎

① JavaScript で表計算アプリを作ってみる
きつね先生 今日は JavaScript で表計算アプリをつくりましょう! わんぽち なんだかとっても難しそうだわん きつね先生 そん...
② JavaScript で表計算アプリを作ってみる
こんにちは!あっきーです! 前回 JavaScript の DOM 機能を使って表計算アプリを一緒に作りましたね! ですが、同じ処理を繰り返したりで無駄に長くなってることからイケてないコードですと言ったかと思います 笑 と...

今回は最終章ということでまた違った実装方法をシェアしていきたいと思います!

前の2つの記事では HTML の要素に記述した属性である id, class, name などをJavaScript で取得することをメインで話しました。

今回はもう全部 JavaScript で HTML 要素も属性も作っちゃおうぜ!ていうお話です。

最近の Web サイトは HTML では必要最低限の静的な構造部分を作り、ユーザーの操作によって変化する動的な HTML 要素は JavaScript で作ることが多いので是非今回でマスターしていってください!

スポンサーリンク

さいしょに

はじめに今回つくるアプリケーションの動作を動画にしましたので確認しましょう!

コードプレビュー

まずは自分のローカル環境で動作確認を行いたい人はしたの HTML コードと JavaScript のコードをテキストエディタにコピペしてファイルを作成してください。

※ HTML の宣言や body タグなどは省略してるので個々で追加しておいてください。

・index.html

<table>
    <tbody id="traffic">
        <tr>
            <td>交通機関</td>
            <td>単価</td>
            <td>利用区分</td>
            <td>合計</td>
        </tr>
        <script>func_traffic()</script>
        <tr>
            <td align="right" colspan="3">合計</td>
            <td>
                <input type="text" class="field_total" readonly="readonly">
            </td>
        </tr>
    </tbody>
</table>
<table>
    <tbody id="hotel">
        <tr>
            <td>宿泊費</td>
            <td>単価</td>
            <td>泊数(数量)</td>
            <td>合計</td>
        </tr>
        <script>func_hotel()</script>
        <tr>
            <td align="right" colspan="3">合計</td>
            <td>
                <input type="text" class="field_total" readonly="readonly">
            </td>
        </tr>
    </tbody>
</table>
総合計<input type="text" name="all_total" readonly="readonly">
<input id="button" type="button" value="確認">
<script>add_listeners()</script>

・app.js

const num_row = 3
const num_opt = 3
var trafficItem = new Array("電車", "バス", "タクシー")
var whichTraffic = new Array("", "片道", "往復")

function func_traffic () {
  var root = document.getElementById('traffic')

  for (var i = 0; i < num_row; ++i) {
    var tr = document.createElement('tr')
    {
      var td = document.createElement('td')
      var sel = document.createElement('select')
      
      for(var j = 0; j < trafficItem.length; j++) {
          var opt = document.createElement('option')
          opt.text = trafficItem[j]
          sel.appendChild(opt)
      }
      td.appendChild(sel)
      tr.appendChild(td)
    }
    {
      var td = document.createElement('td')
      var ipt = document.createElement('input')
      ipt.type = 'text'
      ipt.setAttribute('class', 'price')
      td.appendChild(ipt)
      tr.appendChild(td)
    }
    {
      var td = document.createElement('td')
      var sel = document.createElement('select')
      sel.setAttribute('class', 'traffic')
      
      for(var k = 0; k < whichTraffic.length; k++) {
          var opt = document.createElement('option')
          opt.value = [k]
          opt.text = whichTraffic[k]
          sel.appendChild(opt)
      }
      td.appendChild(sel)
      tr.appendChild(td)
    }
    {
      var td = document.createElement('td')
      var ipt = document.createElement('input')
      ipt.type = 'text'
      ipt.setAttribute('class', 'total')
      td.appendChild(ipt)
      tr.appendChild(td)
    }
    root.appendChild(tr)
  }
}

function func_hotel () {
  var root = document.getElementById('hotel')

  for (var i = 0; i < num_row; ++i) {
    var tr = document.createElement('tr')
    {
      var td = document.createElement('td')
      var sel = document.createElement('select')

      for(var j = 0; j < trafficItem.length; j++) {
          var opt = document.createElement('option')
          opt.text = trafficItem[j]
          sel.appendChild(opt)
      }
      td.appendChild(sel)
      tr.appendChild(td)
    }
    {
      var td = document.createElement('td')
      var ipt = document.createElement('input')
      ipt.type = 'text'
      ipt.setAttribute('class', 'price')
      td.appendChild(ipt)
      tr.appendChild(td)
    }
    {
      var td = document.createElement('td')
      var sel = document.createElement('select')
      sel.setAttribute('class', 'count')
        
      for(var k = 1; k <= num_opt; k++) {
          var opt = document.createElement('option')
          opt.text = [k]
          sel.appendChild(opt)
      }        
      td.appendChild(sel)
      tr.appendChild(td)
    }
    {
      var td = document.createElement('td')
      var ipt = document.createElement('input')
      ipt.type = 'text'
      ipt.setAttribute('class', 'total')
      td.appendChild(ipt)
      tr.appendChild(td)
    }
    root.appendChild(tr)
  }
}

document.addEventListener('change', add_listeners, false)
function add_listeners() {
    var price = document.querySelectorAll('.price')
    var total = document.querySelectorAll('.total')
    var traffic = document.querySelectorAll('.traffic')
    var count = document.querySelectorAll('.count')
    var field_total = document.querySelectorAll('.field_total')
    var all_total = document.querySelector('input[name=all_total]')
    
    var index0 = 0
    var index1 = 0
    var ini_val = 0

    for(var i = 0; i < 3; i++){
      index0 += (ini_val = parseInt(price[i].value || 0) * parseInt(traffic[i].value || 0))
      total[i].value = price[i].value == "" ? "" : ini_val
      index1 += (ini_val = parseInt(price[i+3].value || 0) * parseInt(count[i].value || 0))
      total[i+3].value = price[i+3].value == "" ? "" : ini_val
    }

    field_total[0].value = index0
    field_total[1].value = index1;

    var button = document.getElementById('button')
    button.addEventListener("click", function(e){
        e.preventDefault()
        all_total.value = index0 + index1   
    })
}

※ class などでコードが煩雑になり、見やすさが悪くなってしまいそうでしたので CSS に関する要素とコードは省略してますので見た目は動画と異なります。

解説

前の記事と比べると HTML コードがあきらかに短くなってますね!

表題と合計値の部分のみ HTML で記述し表の計算部分であるテキストボックスやセレクトボックスの部分は JavaScript で生成していきます。

上からなんの処理をおこなっているのか順を追って確認していきましょう!

行数とセレクトボックスの中身を定義する

基本的におこなっていく処理としては、テーブルの行を生成するループの中で→親要素(tr)、子要素(td)、孫要素(input, select)を生成→必要に応じて属性を付与の繰り返しです。

なので最初にやることとしては以下になります。

・行数を定義し、ループの回数を設定する
・セレクトボックスの選択肢をループで取得するため配列で定義しておく

コードしては以下の部分になります。

//テーブルの行数を定義
const num_row = 3

//セレクトボックスの数量を定義
const num_opt = 3

//セレクトボックスの選択肢を定義
var trafficItem = new Array("電車", "バス", "タクシー")

//セレクトボックスの選択肢を定義
var whichTraffic = new Array("", "片道", "往復")

テーブル構造を DOM で生成する

さきほどループの設定をしたのでテーブルを作っていきます。

行数を生成する大枠になる部分のループ分は以下になります。

function func_traffic () {
 //テーブルの全体(tbody)を取得
  var root = document.getElementById('traffic')
 //行数分のループ
  for (var i = 0; i < num_row; ++i) {
    ※中略(テーブルの構造部分を記述していく)
  }
}

これで HTML コードの部分であらかじめ記述しておいた要素を親要素とし、子要素としてテーブルの構造を生成する部分が完成しました。

次に HTML 要素を生成する DOM 操作のメソッドを見ていきましょう。

createElement メソッド

createElement メソッドは HTML 要素を生成します。
生成したい HTML 要素をタグ名で指定して生成することが可能です。

ぶっちゃけここら辺は初学者でもドキュメント読んだ方がわかりやすいので参考にしてください!

Document.createElement
HTML ドキュメントにおいて Document.createElement() メソッドは、tagName で指定した HTML 要素を生成する、あるいは tagName を認識できない場合に HTMLUnknownElement を生成します。XUL ドキュメントでは、指定した XUL 要素を生成します。その他のド...

今回で言えばあらかじめ HTML ファイルで table タグの tbody まで記述しています。
大枠はこれでいいので次は tr 要素を生成して td 要素と順を追って生成していけばテーブルが無事完成ですね!

コードとしては以下の部分になります。

var tr = document.createElement('tr')
{
  var td = document.createElement('td')
  var sel = document.createElement('select')

  for(var j = 0; j < trafficItem.length; j++) {
      var opt = document.createElement('option')
      opt.text = trafficItem[j]
      sel.appendChild(opt)
  }
   td.appendChild(sel)
      tr.appendChild(td)
}

① tr 要素を createElement メソッドをループで生成。
② tr 要素の中に td 要素を入れ子で生成
③ td 要素の中に select 要素を入れ子で生成

以上のように HTML コードでテーブルをつくっていく工程と同じように親要素の中に子要素のタグを記述する工程を JavaScript で生成していきます。

appendChild メソッド

createElement メソッドの欄で記載したコードに appendChild というメソッドも記載されています!

もう察しのいい人なら流れをみればなにをしているかわかってきそうですね。

はじめにセレクトボックスの選択肢を定義しました。
それをループで取得→createElememt メソッドでセレクトボックスの option 属性を生成しループの中身を追加していく。

そして、生成した option 属性を appendChild メソッドで親要素の select 要素にくっつける。

以上の流れから appendChild メソッドは特定の親要素の子要素リストの末尾に属性を追加するメソッドということがわかるかと思います。

ドキュメントも是非参考にしてください!
ブログで解説しておいて投げやりと思われるかも知れませんがドキュメント読むこともめっちゃ大事ですからね!

Node.appendChild
Node.appendChild() メソッドは、特定の親ノードの子ノードリストの末尾にノードを追加します。追加しようとしたノードが既に存在していたら、それは現在の親ノードから除かれ、新しい親ノードに追加されます(他のノードに追加する前にそのノードを親ノードから削除する必要はありません)。

ここまでで table 要素のセレクトボックスの部分が完成です!

setAttribute メソッド

次にインプットのテキスト要素の生成です。
途中まではほぼ同じ処理を行っていますが setAttribute メソッドと新しいメソッドがいます。

コードとしては以下の部分です。

{
  var td = document.createElement('td')
  var ipt = document.createElement('input')
  ipt.type = 'text'
  ipt.setAttribute('class', 'price')
  td.appendChild(ipt)
  tr.appendChild(td)
}

なんか説明しないでもわかりそうですねw
そうです、input 要素に class=”price” を追加しました。

指定の要素に新しい属性を追加、または指定の要素に存在する属性の値を変更することが setAttribute メソッドの役割です。

第1引数に 属性の種類、第2引数に属性名を指定します。

ドキュメントも参考にして理解を深めてください。

element.setAttribute
指定の要素に新しい属性を追加します。または指定の要素に存在する属性の値を変更します。

残りのコードはもう同じ処理の繰り返しですのでゆっくりコードを読んでください。

あとは生成した要素を取得し計算式を組んでいけば完成です。前回の記事で解説してますので今回は割愛させていただきます。

⬇︎⬇︎参考⬇︎⬇︎

② JavaScript で表計算アプリを作ってみる
こんにちは!あっきーです! 前回 JavaScript の DOM 機能を使って表計算アプリを一緒に作りましたね! ですが、同じ処理を繰り返したりで無駄に長くなってることからイケてないコードですと言ったかと思います 笑 と...

コードとしては以下の部分になります。

document.addEventListener('change', add_listeners, false)
function add_listeners() {
    var price = document.querySelectorAll('.price')
    var total = document.querySelectorAll('.total')
    var traffic = document.querySelectorAll('.traffic')
    var count = document.querySelectorAll('.count')
    var field_total = document.querySelectorAll('.field_total')
    var all_total = document.querySelector('input[name=all_total]')
    
    var index0 = 0
    var index1 = 0
    var ini_val = 0
    for(var i = 0; i < 3; i++){
      index0 += (ini_val = parseInt(price[i].value || 0) * parseInt(traffic[i].value || 0))
      total[i].value = price[i].value == "" ? "" : ini_val
      index1 += (ini_val = parseInt(price[i+3].value || 0) * parseInt(count[i].value || 0))
      total[i+3].value = price[i+3].value == "" ? "" : ini_val
    }
    field_total[0].value = index0
    field_total[1].value = index1;
    var button = document.getElementById('button')
    button.addEventListener("click", function(e){
        e.preventDefault()
        all_total.value = index0 + index1   
    })
}

おわりに

3回にわたって DOM 操作について解説してきましたがいかがでしたでしょうか?

これで JavaScript 中級者くらいにはなれたんではないでしょうか?
最近ではフレームワークが主流ですのでわざわざピュア JavaScript で記述する機会も少なくなってきてるのでしょうが、基本をわかってこそフレームワークの恩恵を最大限に引き出せると思っています!

ちなみに僕はフレームワークはほとんど経験ないです。笑

今後ともいろんな実装や勉強方法など記事にしていきますので今後ともよろしくお願いします!

スポンサーリンク
あっきー

元キャバクラ店長から未経験でエンジニアに転職した異端児。

「週4の5時間勤務、月収100万円」を実現させ、ゆるりと生きることを目標に日々パソコンと奮闘している。

自分の経験を元に、未経験からでも挫折しないプログラミングの勉強方法や最新技術や情報などを発信していきます。

あっきーをフォローする
HTML/CSSJavaScript
\良い記事だったらシェアしてね!/
スポンサーリンク
駆け出しエンジニアのつぶやき