1

I am using Stripe and to avoid any issues with PCI compliance the credit card data entered on my forms should never be transmitted from browser to server. Users shall enter credit-card data into forms with Knockout.js.

Mostly as a matter of interest (mostly so I understand better how knockout.js works), I would like to come up with a way to prevent serialization of credit-card data by having an explicit error occur whenever serialization of the data is attempted in the usual knockout.js way (ie ko.toJS or ko.toJSON or ko.mapping.* equivalents).

To achieve this I thought I could do something clever, like this (in CoffeeScript):

class NeverSerialize
  datums = ko.observable()
  blocker = ko.computed(
    read: () -> throw new Error("You shall not pass!")
    deferEvaluation: true
  )

and when ko.toJS/toJSON or equivalent is called it would execute blocker() and that would call the read function and be the end of it.

This idea almost works - as you can see from this jsFiddle. Unfortunately it only executes read() the first time, but it is never called after. I gather this is because there are no observables that read depends upon, so knockout presumes that the value of the computed will not have changed.

So I guess I am curious about two things:

  1. Is this conceptually a sensible way to go about preventing an observable from being serialized with ko.toJS/toJSON? (or, generically, having a function execute whenever a read is called on a computed observable)

  2. How would one go about having a computed variable's read function called every time it is accessed (i.e. avoid caching it)?

I am just curious about how one might go about this sort of thing with Knockout.js.

4

3 に答える 3

2

それをすべて行うのではなく、toJSONシリアル化するプロパティを含むオブジェクトを返す関数を定義するだけです。つまり、ビューモデルのコピーを作成し、シリアル化したくないコピーからプロパティを削除します。

function ViewModel(model) {
    this.name = ko.observable(model.name);
    this.password = ko.observable(model.password);

    this.toJSON = function () {
        var copy = ko.toJS(this);
        delete copy.password;
        return copy;
    }
}

あなたが本当にこれをしたいのなら、私はあなたがこれをすることができると思います。このko.toJS関数は、オブジェクトのすべてのプロパティを調べ、値を新しいオブジェクトにマップします。したがって、観察可能でない場合は、単にコピーします。そうでない場合は、呼び出し(読み取り)します。ノックアウトをだまして無条件にobservableを呼び出す必要があるため、読み取り時に常にエラーがスローされる可能性があります。

非キャッシングバージョンとなる新しい監視可能な階層を作成できますが、それはおそらく必要のない多くのことです。最終的にエラーをスローするオブザーバブルを作成する必要があります。したがって、あなたができることは、エラーをスローし、ノックアウトをだまして、それが観察可能であると思わせる関数を作成することです。幸いなことに、ノックアウトは、特別なプロパティを介してプロトタイプとして観察可能であることを確認することで、これをチェックします。

ko.errorObservable = function (thrower) {
    function errorObservable() {
        if (typeof thrower === 'function') {
            thrower();
        }
    }
    // trick knockout into thinking this is an observable so it will be invoked
    errorObservable[ko.observable.protoProperty] = ko.observable;
    return errorObservable;
};

次に、ビューモデルにオブザーバブルを追加するだけで、設定が完了します。

function ViewModel(model) {
    this.name = ko.observable(model.name);
    this.password = ko.observable(model.password);
    this._neverSerialize = ko.errorObservable(function () {
        throw new Error("Serialization of this model is prohibited.");
    });
}

もちろん、これは文書化されていない動作に依存しています。ノックアウトがこれらのことを決定する方法は、将来変更される可能性があります。自己責任。

于 2012-11-18T05:56:55.827 に答える
2

この投稿を最初に読んだ後に偶然見つけた代替案:

enumerableプロパティのオプションを設定すると、falseシリアル化されません。

たとえば、次のようにオブジェクトを作成する場合Object.create()

const obj = Object.create(objProto, {
        name: { value: name, enumerable: true },
        items: { value: items, enumerable: false }
    });

この場合items、からのシリアル化された文字列には表示されませんko.toJSON()

于 2015-10-02T15:28:26.323 に答える
1

これがに関する記事ですknockmeout

これは基本的にジェフの答えと同じ方法ですが、詳細があります。

http://www.knockmeout.net/2011/04/controlling-how-object-is-converted-to.html

于 2014-06-19T05:20:03.560 に答える