数値はカンマ区切りで表示して欲しい!!
Web系のプロジェクトでコレ系の要望をよく言われるけど、
HTMLのinput[type=number]ってそこまで賢くないんだから、
「うるせー、そんなオンプレでやってるようなことWebで要望すんなや!」
って、めっちゃ言いたい気持ちを笑顔で押し殺して、
サードのライブラリとかはじめからそういったマスク入力が出来るライブラリ(VueだとPrimeVue)を選定するわけですが、毎回使えるわけでもないので。。。
だったら自分で作ってみたらいいんでね?
という、車輪の再発明みたいなことをしてみようかと。
実装環境
まぁタイトルにありますが、IONICとAngular(Standoalone)で作ってみました。
※多分どのバージョンのIONICでも出来るはず
今回の動きとしては
ion-textの表示時・入力時の動きを以下のようにしました。
- 表示:フォーマットしたもの
- 入力:フォーマットを外したものを編集
そんなわけでソース
<ion-input [formControl]="control"
(ionFocus)="focus()"
(ionBlur)="blur($event)"
(ionChange)="change($event)"></ion-input>
ion-textに対してfocus/blur/changeイベントを登録
export class FormInputNumberComponent implements OnInit {
// 入力制御用のFormControl
protected readonly control = new FormControl('');
private _value: string;
@Input()
get value() {
return this.control.value;
}
set value(value: string) {
// Changeイベントを発生させるかの判定用に値を保持する
this._value = value;
// {emitEvent: false} でChangeイベントが発生しないように設定
this.control.setValue(this.formatNumber(param.value), {
emitEvent: false,
});
}
@Output() changeEvent: EventEmitter<value?: string> = new EventEmitter();
constructor() {}
ngOnInit() {
console.debug('FormInputNumberComponent ngOnInit');
}
focus() {
// フォーカスが当たったときは、カンマを取り除いて詰め直す
// {emitEvent: false} でChangeイベントが発生しないように設定
this.control.setValue(this._item.value?.replaceAll(',', ''), {
emitEvent: false,
});
}
blur($event) {
// フォーカスが外れた時に、入力されてる値を整形して詰め直す
// {emitEvent: false} でChangeイベントが発生しないように設定
this.control.setValue(this.formatNumber($event.detail.target.value), {
emitEvent: false,
});
}
private formatNumber(val: string): string {
const num = Number.parseInt(val);
return isNaN(num)
? ''
: num.toLocaleString('ja-JP');
}
change($event) {
// 値が変わってるときだけイベント発火
if (this._value !== $event.detail.value){
// 入力された値を親コンポーネントに返す
this.changeEvent.emit($event.detail.value);
// 整形した値を返したい場合は以下
// this.changeEvent.emit(this.formatNumber($event.detail.value));
}
}
}
まとめ
「入力中もフォーマットされた状態でやれや」的なクレームがあるかもしれませんが、
とりあえず表示だけでも出来てりゃええやろということで今回はここまで。
ionBlurじゃなくてionInputとかで入力監視してれば全然出来るんだろうけど、ソレやると整形後のカーソルの位置操作とかも必要になるんじゃないかなと言うめんどくささもあり、とりあえず即席でこんだけ動けばええやろ感覚で作ってみた次第です。
※そこらへんはきっと、もっと賢い人がちゃんと作ってくれるはず!
補足
ちなみにですが、Number.parseIntって結構使えない子みたいなので、数値かどうかの確認は
Number.parseInt したものを isNaNでチェックするよりも、
きちんと正規表現とかでチェックしたほうが良いかと。