こんなやつ: http://jsfiddle.net/MKGaru/xd9vs2zp/
入力フォームで数値を入力させる際、
小数点以下は 何位まで~ とか
3桁ごとに、 カンマで区切りたい とか
正の整数だけにしたい とか
いろいろな要求が出てくることがある。
HTML5の input type=number とvalidationだけでは対応できないことが多いし、そもそも対応ブラウザが少なすぎる。
ほしかった機能次のとおり。
機能
- IMEの状態に関係なく、半角数値として入力
- 小数点何位まで扱うか 、 またその際の値丸め(四捨五入等)の設定
- 3桁毎の区切り文字の指定
- 小数点の区切り文字の指定
- 正の数のみ または 負の数のサポート の設定
- prefixの指定
- suffixの指定
- 0 と 未入力の区別
これを実装してみた
依存
- knockout.js
- knockout-es5 (単純にko.computedのreadとwriteに書き換えれば不要にできるかも)
-
sugar.js
(サンプルではknockout.punchesも利用)
仕様
Objectの、
生数値用のpropertyに、
整形数値用のformattedProperty を追加する。
formattedPropertyに整形された数字をsetすると 生数値がpropertyにsetされる。
formattedPropertyを参照すると、整形されたpropertyをgetする
空文字を formattedProperty に設定すると、 null が propertyにsetされる。
propertyがnullのとき、formattedPropertyは 空文字になる。
使用方法
-
numberFormattedProperty(
プロパティの属するオブジェクト
,"プロパティ名
",{オプション
}); -
オプション
key | default | description |
---|---|---|
prefix | '' | 頭に付与する文字列 |
suffix | '' | 尻に付与する文字列 |
place | 0 | 小数点位置 |
thousands | ',' | 3桁毎の区切り文字 |
decimal | '.' | 小数点区切り文字 |
allowMinus | false | 負の数の許可 |
round | 'round' | 丸め方式 (round , ceil , floor (四捨五入, 切上げ, 切り捨て)) |
例えば、vmのpriceというプロパティを、通貨入力用に拡張する場合
(ここでいう通貨入力とは、
- prefixに円マークを指定して、
- 正の整数で、
- 3桁毎に カンマ区切り
を期待する場合)
ko.track( vm );
で、Objectをtrackした後に、
numberFormattedProperty(vm,"price",{prefix:'¥'});
で、vm の price
プロパティを整形したプロパティformattedPrice
をvmに追加する
サンプル
<dl>
<dt>Formatted Price</dt>
<dd><input type="text" class="number" data-bind="textInput:formattedPrice" /></dd>
<dt>Raw Price</dt>
<dd>{{price}}</dd>
<dt>Formatted Quantity</dt>
<dd><input type="text" class="number" data-bind="value:formattedQuantity" /></dd>
<dt>Raw Quantity</dt>
<dd>{{quantity}}</dd>
</dl>
function VM(){
var vm = this;
vm.price=130;
vm.quantity=2.15;
ko.track(vm);
numberFormattedProperty(vm,"price",{prefix:'¥'});
numberFormattedProperty(vm,"quantity",{suffix:'kg',place:2});
};
ko.applyBindings(new VM());
data-bindの方法は、valueやknockout3.2から利用可能なtextInputどちらでも利用可能だが、
正の整数のみの 入力は、textInputだと入力中の文字が即時反映されるのでうれしい場合もあるが、
入力毎(キーイベント毎)に正規表現による数値判定が行われるため、
3.14
と入力しようと思って
3.
まで入力した段階で数値化されて
3
に戻されてしまうため具合が悪い。
なので、負の数 や 小数などを扱う場合には、valueバインディングを推奨
(value は フォーカスが外れてから判定される )
実装
function numberFormattedProperty(model, prop, option) {
var _default = {
prefix: '',
suffix: '',
place: 0,
thousands: ',',
decimal: '.',
allowMinus: false,
round: 'round' // round | ceil | floor (四捨五入, 切上げ, 切り捨て)
};
option = ko.utils.extend(_default, option);
ko.defineProperty(model, "formatted" + prop.camelize(), {
get: function () {
var value = ko.unwrap(model[prop]);
if (value == null)
return "";
return option.prefix + value[option.round](option.place).format(option.place, option.thousands, option.decimal) + option.suffix;
},
set: function (value) {
model[prop] = NaN; //force mutant event
var replacer = new RegExp('[^' + (option.allowMinus ? '\\-' : '') + '0-9\\.]' + (option.place > 0 ? '||[' + RegExp.escape(option.decimal) + ']' : ''), 'g'); // 丸めるケタが小数点以下なら、 小数点文字の入力を許可
if (value == '')
model[prop] = null;
else
model[prop] = (+value.hankaku().replace(replacer, ''))[option.round](option.place);
}
});
};