LoginSignup
4
5

More than 5 years have passed since last update.

KnockoutJSで、整形された数値入力をする方法

Last updated at Posted at 2015-02-05

こんなやつ: http://jsfiddle.net/MKGaru/xd9vs2zp/


入力フォームで数値を入力させる際、
 小数点以下は 何位まで~ とか
 3桁ごとに、 カンマで区切りたい とか
 正の整数だけにしたい とか
いろいろな要求が出てくることがある。

HTML5の input type=number とvalidationだけでは対応できないことが多いし、そもそも対応ブラウザが少なすぎる。
ほしかった機能次のとおり。

機能

  • IMEの状態に関係なく、半角数値として入力
  • 小数点何位まで扱うか 、 またその際の値丸め(四捨五入等)の設定
  • 3桁毎の区切り文字の指定
  • 小数点の区切り文字の指定
  • 正の数のみ または 負の数のサポート の設定
  • prefixの指定
  • suffixの指定
  • 0 と 未入力の区別

これを実装してみた

依存

仕様

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の方法は、valueknockout3.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);
        }
    });
};
*ぶっちゃけ内部処理はsugarjs依存
4
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
5