1

ノックアウトとマッピングプラグインを使用して、ビューモデルを自動的に作成しています。ビューモデルには、テキストボックスにバインドする大量の量があります。ユーザーがテキストボックスの金額を変更するとき、私が欲しいのは、入力したものが数字であり、それが0より大きいことを確認することだけです。そうでない場合は、入力したものを0に置き換えます。これは次のようになります。それはとてもシンプルなはずです...カスタムバインディングまたはサブスクライブ機能を備えています。

ノックアウト検証について読んでいることはすべて、エクステンダーと計算されたオブザーバブルの読み取り/書き込み、またはさらに別のプラグイン(jquery検証など)の追加について説明しています。それらはすべて状況に対してやり過ぎのように思われ、エクステンダー/計算されたオブザーバブルは、検証するオブザーバブルごとに明示的に宣言する必要があります。マッピングプラグインを使用して自動的に作成される量がたくさんあるので、これは合理的ではないようです。

どんな助けでも大歓迎です!

4

2 に答える 2

7

特定のシナリオでは、これを処理する1つの方法は、値をインターセプトして検証を実行できるカスタムバインディングを作成することです。これは、バインドするカスタムバインディングで計算された書き込み可能ファイルを作成することで実行できます。利点は、オブジェクト作成をカスタマイズするマッピングプラグインについて心配する必要がないことです。

次のようになります。

ko.bindingHandlers.positiveNumericValue = {
    init : function(element, valueAccessor, allBindingsAccessor) {
        var underlyingObservable = valueAccessor();
        var interceptor = ko.computed({
            read: underlyingObservable,
            write: function(newValue) {
                var current = underlyingObservable(),
                    valueToWrite = isNaN(newValue) ? 0 : parseFloat(+newValue);

                if (valueToWrite < 0) {
                   valueToWrite = 0;   
                }

                //only write if it changed
                if (valueToWrite !== current) {
                    underlyingObservable(valueToWrite);
                } else {
                    //if the rounded value is the same as it was, but a different value was written, force a notification so the current field is updated to the rounded value
                    if (newValue !== current) {
                        underlyingObservable.valueHasMutated();
                    }
                }   
            } 
        });
        ko.bindingHandlers.value.init(element, function() { return interceptor }, allBindingsAccessor);
    },  
    update : ko.bindingHandlers.value.update
};

サンプルは次のとおりです:http://jsfiddle.net/rniemeyer/2TnSM/

別の方法は、書き込み可能な計算を作成するオプションを使用してオブザーバブルを拡張することです。

シナリオでは、次のようになります。

ko.observable.fn.forcePositive = function() {
    var underlyingObservable = this;
    if (!this.forcePositiveInterceptor) {
         this.forcePositiveInterceptor = ko.computed({
            read: this,
            write: function(newValue) {
                var current = underlyingObservable(),
                    valueToWrite = isNaN(newValue) ? 0 : parseFloat(+newValue);

                if (valueToWrite < 0) {
                   valueToWrite = 0;   
                }

                //only write if it changed
                if (valueToWrite !== current) {
                    underlyingObservable(valueToWrite);
                } else {
                    //if the rounded value is the same as it was, but a different value was written, force a notification so the current field is updated to the rounded value
                    if (newValue !== current) {
                        underlyingObservable.valueHasMutated();
                    }
                }   
            } 
        });
    }            

    return this.forcePositiveInterceptor;        
};

次に、次のようにバインドします。

<input type="text" name="age" data-bind="value: age.forcePositive()" />

ここで実装した方法では、関数として呼び出す必要があるforcePositive()ため、書き込み可能オブジェクトが初期化されます。これは、カスタマイズなしでマッピングプラグインを使用し、この機能を使用するオブザーバブルでこれを実行できるようにするためです。

サンプル: http: //jsfiddle.net/rniemeyer/Dy4MH/

どちらの選択でもあなたのシナリオにはうまくいくと思います。通常のバインディングを使用しながらこれらをさらに追加できるように、私はおそらく2番目の選択肢を好みます。

于 2012-09-06T15:31:27.193 に答える
1

速くて小さいもの

http://jsfiddle.net/gxfup/1/

編集:

マッピングプラグインにビューモデルを定義させたくないので、プロトタイプのビューモデルを使用します(上記の例のように、マッパープラグインにその上にマッピングさせます)。

ViewModel = function (data) {
    this.number = ko.observable().extend({ number: true });
    return ko.mapping.fromJS(data, {}, this);
};
于 2012-09-06T15:38:47.263 に答える