【JavaScript】 料金の自動計算を非同期でActiveHash(アクティブハッシュ )のプルダウン選択をして表示させる。

#はじめに


javascriptとプルダウンの選択方式で（アクティブハッシュ）非同期的に表示を変える方法を紹介します。
具体的には、予め決められた「料金」に対して、アクティブハッシュ内からdate属性で「数列」を取得し、計算をする実装をします。
要するに、「料金」X「人数」です。

![ezgif.com-gif-maker.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/769854/9dfa5920-5442-2fb0-fb8d-c1462c826a12.gif)



前提
基本的なMVCとアクティブハッシュは既に実装済みです。
こちらを参考にしてください。

【Rails】ActiveHash（アクティブハッシュ）の導入と「確認」→「保存」→「表示」
https://qiita.com/AKI3/items/022ad68e22f798d40ad9

###目次
1. date属性の付与
2. javascrip

#開発環境
ruby 2.6.5
rails 6.0.0


#実装
それでは実装していきます〜














#1. date属性の付与


###マイグレーションファイルの編集

```db/migrate/2020XXXXXXXX_create_event.rb
class CreateEvents < ActiveRecord::Migration[6.0]
  def change
    create_table :events do |t|
      t.string    :price
      t.integer   :num_id

      t.timestamps
    end
  end
end

```
保存で必要なカラム`price`と`num_id`（ActiveHashのid）を記述します。

```
rails db:migrate
```


###モデル作成・編集

そして、ActiveHashモデルを作成します。
作成したActiveHashモデルの記述を編集します。

```app/models/num.rb
class Num < ActiveHash::Base
  self.data = [
    { id: 0, name: '--' },
    { id: 1, name: '1', multiple:1 },
    { id: 2, name: '2', multiple:2 },
    { id: 3, name: '3', multiple:3 },
    { id: 4, name: '4', multiple:4 },
    { id: 5, name: '5', multiple:5 },
    { id: 6, name: '6', multiple:6 },
    { id: 7, name: '7', multiple:7 },
    { id: 8, name: '8', multiple:8 },
    { id: 9, name: '9', multiple:9 },
    { id: 10, name: '10', multiple:10 },
    { id: 11, name: 'お問い合わせください' },
  ]
end
```

`name`属性の後にdeta属性`multiple:1`と数列で数字を入れて追記します。
今回は`multiple`をdeta属性を使用してますが、お好みで編集できます。
また`multiple:1`の数列「１」も変更可能です。 
例えば、こんな感じです。

```
id: 1, name: '1', multiple:1 
 #下記に様に編集できます
id: 1, name: 'コーラ', multiple:150 
```
とする事もできます。通常のActiveHashではname属性しか扱いませんが、date属性を使う事で様々な値を取得できます。
このdate属性は、データを取得際JavaScriptで取得します。

次にビューで入力フォームを作ります。





###ビューの作成

```html:app/events/viwes/index.erb
<h1>Events#new</h1>
<p>Find me in app/views/events/new.html.erb</p>

<div class="#">
  <div class="#">
    <P>一人あたりの値段</P>
      <div class="#" >
        <p>¥<span id="one_price">10,000</span></p>
      </div>
    <P>合計金額</P>  
      <div class="#" id="total_price">
        <p>¥0</p>
      </div>
  </div>

  <div class="#">
    <%= form_with(model: @event, url:confirm_events_path, local: true) do |f| %> #←ここは注意

      <div>
        <%= f.hidden_field :price, id: "f_price"  %> #←ここはhidden
      </div>

      <div class="#">
        <%= f.label :num, '参加人数' %>
          #ここからプルダウンにする記述#
          <% num_options = Num.order(:id).map { |c| [c.name, c.id, data: { multiple: c.multiple }] } %>
          <%= f.select(:num_id, num_options, {}, {class:"#", data:{select:0}, id:"num" }) %>
          #ここまで#
      </div>
      <div class="submit">
        <%= f.submit "submit", class:"#" %>
      </div>
    <% end %>
  </div>
</div>
```

 `<%= form_with(model: @event, url:confirm_events_path, local: true) do |f| %>`
pathは`rails routes`で調べてください。今回は確認画面を挟んだ実装をしているので上記の様なpathになってます。

ポイントはプルダウンのoptionsデータ属性です。

| 項目| 名前 |
|:-:|:-:|
|変数名    |num_options|
|data属性名|multiple|
|id       |num|

としました。
ここまでが下地で続いてJavaScriptです。














#2. javascrip


最初javascriptのapplication.jsファイルを編集します。

```javascript:app/javascript/packs/application.js
//省略

require("@rails/ujs").start()
// require("turbolinks").start() ←ここをコメントアウト
require("@rails/activestorage").start()
require("channels")
require("../price") //←ここに追記

//省略
```





javascript配下新しいファイルを作成します。
今回はpriceという名前にします。


![スクリーンショット 2020-12-02 12.59.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/769854/9e62d58d-2adc-6d35-2777-3edde494a519.png)



まず型枠を記述します。

```app/javascript/price.js
const price = function () {
  const onePrice = document.getElementById("one_price");
  const totalPrice = document.getElementById("total_price");
}

window.addEventListener("load", price);
```

一人当りの料金を`one_price`合計を`total_price`としてます。



ビューのプルダウンで人数を選択するとJavaScriptが発火する様に記述します。

```app/javascript/price.js
  const selectNum = document.getElementById("num");
    selectNum.addEventListener('change', function (){
```

idが`num`のdata属性`multiple`の値を取る。

```app/javascript/price.js
      // numのdata属性の値を取る
      const numSelectBox = document.getElementById("num");
      const dataNum = numSelectBox.options[ numSelectBox.selectedIndex].getAttribute("data-multiple");
```

細かくなりますが、一人料金のidを取得したあと値を数列に変換して、さらにカンマを除去します。

```app/javascript/price.js
      // 一人料金のidを取得
      const priceOne = document.getElementById("one_price");
      //値を数列にする
      const displayPriceOne = priceOne.innerHTML;
      //カンマを除去する
      const displayPriceOneInteger = Number( displayPriceOne.replace(/,/, '') );
```


計算して、表示ように変換して、表示します。

```app/javascript/price.js
      // 計算する
      const total = (displayPriceOneInteger*dataNum);
      // 正規表現でカンマ区切りに直して日本円に変換する
      const totalComma = total.toLocaleString('ja-JP', { style: 'currency', currency: 'JPY'});
      // 表示する
      totalPrice.innerHTML = totalComma;
```


最後、ビューで表示した値をvalueプロパティでtextarea(今回はhidden_field)要素に値を代入します。

```app/javascript/price.js
      // ----<フォームに入力>
      // 合計金額の値を取得 
      const displayPriceTotal = totalPrice.innerHTML;
      // 取得した合計金額をフォームに入力
      document.getElementById("f_price").value = displayPriceTotal;
    });
```



つなげると以下の様になります。

```app/javascript/price.js
const price = function () {
  const totalPrice = document.getElementById("total_price");
  const onePrice = document.getElementById("one_price");

  // ------<人数を選択した時の計算>
  const selectNum = document.getElementById("num");
    selectNum.addEventListener('change', function (){
      // numのdata属性の値を取る
      const numSelectBox = document.getElementById("num");
      const dataNum = numSelectBox.options[ numSelectBox.selectedIndex].getAttribute("data-multiple");
      // 一人料金のidを取得
      const priceOne = document.getElementById("one_price");
      //値を数列にする
      const displayPriceOne = priceOne.innerHTML;
      //カンマを除去する
      const displayPriceOneInteger = Number( displayPriceOne.replace(/,/, '') );
      // 計算する
      const total = (displayPriceOneInteger*dataNum);
      // 正規表現でカンマ区切りに直して日本円に変換する
      const totalComma = total.toLocaleString('ja-JP', { style: 'currency', currency: 'JPY'});
      // 表示する
      totalPrice.innerHTML = totalComma;
      // ----<フォームに入力>
      // 合計金額の値を取得 
      const displayPriceTotal = totalPrice.innerHTML;
      // 取得した合計金額をフォームに入力
      document.getElementById("f_price").value = displayPriceTotal;
    });
}

window.addEventListener("load", price);
```


完成です！！




#まとめ
以上、 JavaScriptとActiveHash(アクティブハッシュ )を使って、非同期で料金の自動計算をする方法でした。



最後に
私はプログラミング初学者ですが、同じ様に悩んでる方々の助けになればと思い、記事を投稿しております。
それでは、また次回お会いしましょう〜



#参考
https://www.sejuku.net/blog/23998
https://techacademy.jp/magazine/22426
https://lealog.hateblo.jp/entry/2013/02/28/005010
https://lab.syncer.jp/Web/JavaScript/Snippet/29/

【Rails】ActiveHash（アクティブハッシュ）の導入と「確認」→「保存」→「表示」
https://qiita.com/AKI3/items/022ad68e22f798d40ad9