はじめに
桁数が多い数字は桁数が合っているか判断しづらいです。判断しやすくするために、3桁区切りでカンマを入れます。自ら3桁区切りでカンマを入れることも可能ですが、それはやりたくないでしょう。
そこで、HotwireのStimulusを使って、数字が自動フォーマットされるようにしました。
環境
- Rails 7.0.7
- Ruby 3.2.2
実装
ただ、数字をフォーマットすればいいだけに思いますが、実際は違います。データベースに保存する時にはカンマを取り除く必要があります。カンマがついた状態では、データベースで数値として扱えないからです。数値として扱えないと、年収が1,000,000円以上のユーザーを検索するのも難しくなります。数値として扱うために、データベースに保存する前に、数字からカンマを取り除く必要があります。
つまり、以下のことができればいいということです。
- 入力時に数字にカンマをつける
- 登録するボタンを押した時に数字からカンマを取り除く
1. 入力時に数字にカンマをつける
数字を入力する<input>
要素に入力があるたびに、数字にカンマがつくようにします。
数字にカンマをつけるためのstimulus controllerを作成します。
import { Controller } from '@hotwired/stimulus'
import numeral from 'numeral'
// Connects to data-controller="numeral"
export default class extends Controller {
format(event) {
event.target.value = numeral(event.target.value).format();
}
}
numeral により、数字をフォーマットしたり、フォーマットしたものを数字に戻すことができます。
format
メソッドが実行されると、そのトリガーとなったHTML要素のvalue
をフォーマットします。つまり、3桁区切りでカンマがつきます。
以下のようにdata-controller
とdata-action
をHTML要素の属性として持たせれば、入力のたびに数字がフォーマットされます。
= simple_form_for user, html: { 'data-controller': :numeral } do |f|
= f.input :name
= f.input :annual_income, as: :string, input_html: { 'data-action': 'numeral#format' }
= f.input :phone_number
= f.submit class: 'btn btn-primary'
2. 登録するボタンを押した時に数字からカンマを取り除く
このままだと、数字にカンマが入ったままになっているので、数値としてデータベースに保存できません。なので、以下のようにして、登録するボタンを押した時に数字からカンマが取り除かれるようにします。
import { Controller } from '@hotwired/stimulus'
import numeral from 'numeral'
// Connects to data-controller="numeral"
export default class extends Controller {
static targets = ['input'];
format(event) {
event.target.value = numeral(event.target.value).format();
}
submit() {
this.inputTargets.forEach(input => input.value = numeral(input.value).value());
}
}
= simple_form_for user, html: { 'data-controller': :numeral } do |f|
= f.input :name
= f.input :annual_income, as: :string, input_html: { 'data-action': 'numeral#format', 'data-numeral-target': 'input' }
= f.input :phone_number
= f.submit class: 'btn btn-primary', 'data-action': 'numeral#submit'
submit
メソッドをすると、数字からカンマが取り除かれます。<button>
要素に'data-action': 'numeral#submit'
属性を持たせて、登録するボタンを押した時にsubmit
メソッドが実行されるようにしています。
数字からカンマを取り除く<input>
要素は、Stimulusのtargetsを使って参照できるようにしています。<input>
要素に'data-numeral-target': 'input'
属性を持たせて、stimulus controllerでstatic targets = ['input']
を定義することで、<input>
要素をstimulus controller内で参照できます。詳しくはリファレンスを参照ください。
submit
メソッドではthis.inputTargets
で、'data-numeral-target': 'input'
属性を持ったHTML要素の配列を参照しています。この配列の各要素のvalue
からカンマを取り除いています。
まとめ
HotwireのStimulusを使って、数字が自動フォーマットされるようにしました。
Stimulusのtargetsを利用して、数字からカンマを取り除きました。targetsは、stimulus controller内でHTML要素を参照したいときに便利です。targetsとなり得るHTML要素は、data-controller
属性を持ったHTML要素内に絞れるところも良いところだと思います。
メンテナブルな改善
@aki77 さんから以下の指摘を受けて、numeral_controller を以下のように改善してみました。
- ブラウザの標準機能でやった方がメンテナブルだと思う
- numeral は、6年間更新がない
import { Controller } from '@hotwired/stimulus'
// Connects to data-controller="numeral"
export default class extends Controller {
static targets = ['input'];
connect() {
this.numberFormat = new Intl.NumberFormat();
}
inputTargetConnected(element) {
element.value = this.numberFormat.format(element.value);
}
format(event) {
event.target.value = this.numberFormat.format(event.target.value);
}
submit() {
this.inputTargets.forEach(input => input.value = this._unformat(input.value));
}
_unformat(formattedNumber) {
return formattedNumber.replace(/,/g, '');
}
}