web-dev-qa-db-ja.com

Knockoutビューモデルへの変更の検出

確かにこれは答えが非常に簡単な質問ですが、ノックアウトビューモデルのプロパティが変更されたかどうかを判断する簡単な方法はありますか?

63
user1389723

エクステンダーを使用します。

ko.extenders.trackChange = function (target, track) {
    if (track) {
        target.isDirty = ko.observable(false);
        target.originalValue = target();
        target.setOriginalValue = function(startingValue) {
            target.originalValue = startingValue; 
        };
        target.subscribe(function (newValue) {
            // use != not !== so numbers will equate naturally
            target.isDirty(newValue != target.originalValue);
        });
    }
    return target;
};

次に:

self.MyProperty= ko.observable("Property Value").extend({ trackChange: true });

これで、次のように検査できます。

self.MyProperty.isDirty()

また、何らかの変更が加えられたかどうかを確認するために、一般的なviewModelトラバースを記述することもできます。

self.isDirty = ko.computed(function () {
    for (key in self) {
        if (self.hasOwnProperty(key) && ko.isObservable(self[key]) && typeof self[key].isDirty === 'function' && self[key].isDirty()) {
            return true;
        }
    }
});

...そして、viewModelレベルで確認するだけです

self.isDirty()
98
Brett Green

監視するプロパティをサブスクライブできます。

myViewModel.personName.subscribe(function(newValue) {
    alert("The person's new name is " + newValue); 
});

これは、personNameが変更されたときにアラートを出します。

わかりましたので、あなたはあなたのモデルで何かが変更されたときに知りたいです...

var viewModel = … // define your viewModel

var changeLog = new Array();  

function catchChanges(property, value){
    changeLog.Push({property: property, value: value});
    viewModel.isDirty = true;
}

function initialiseViewModel()
{
    // loop through all the properties in the model
    for (var property in viewModel) {

        if (viewModel.hasOwnProperty(property)) { 

            // if they're observable
            if(viewModel[property].subscribe){

                // subscribe to changes
                viewModel[property].subscribe(function(value) {
                    catchChanges(property, value);
                });
            }
        }
    }
    viewModel.isDirty = false;
}

function resetViewModel() {
    changeLog = new Array();  
    viewModel.isDirty = false;
}

(テストしていない-しかし、あなたはアイデアを得る必要がある)

49
web_bod

Knockout-Validationプラグイン の使用を検討してください

以下を実装します。

yourProperty.isModified()-ユーザーが値を変更したかどうかを確認します。

yourProperty.originalValue-したがって、値が実際に変更されたかどうかを確認できます。

便利な他の検証機能と一緒に!

乾杯

5
dzl-pt

これには、以下のプラグインを使用できます。

https://github.com/ZiadJ/knockoutjs-reactor

たとえば、コードを使用すると、viewModel内のすべての変更を追跡できます。

ko.watch(someViewModel, { depth: -1 }, function(parents, child) { 
    alert('New value is: ' + child());
});

PS:現時点では、これは配列内にネストされたサブスクライブ可能オブジェクトでは機能しませんが、それをサポートする新しいバージョンは準備中です。

更新:v1.2bで動作するようにサンプルコードがアップグレードされ、配列項目とサブスクライブ可能インサブスクライブプロパティのサポートが追加されました。

3
Ziad

AcceptChangesを使用できるように@Brett Greenコードを適応させ、モデルをダーティでないとマークし、モデルを追跡可能としてマークするより良い方法を追加しました。コードは次のとおりです。

var viewModel = {
    name: ko.observable()   
};

ko.track(viewModel);

http://jsfiddle.net/david_freire/3HZEu/2/

2
David Freire

私は同じ問題を抱えていました、私はサーバーにデータを送り返すためにviewModelの変更を観察する必要がありました、誰かがまだ興味を持っているなら、私はいくつかの研究を行いました、これはiv'eが組み立てることができた最高のソリューションです:

function GlobalObserver(viewModel, callback) {  
    var self = this;
    viewModel.allChangesObserver = ko.computed(function() {
        self.viewModelRaw = ko.mapping.toJS(viewModel);
    });
    viewModel.allChangesObserver.subscribe(function() {
        callback(self.viewModelRaw);
    });
    self.dispose = function() {
        if (viewModel.allChangesObserver)
            viewModel.allChangesObserver.dispose();
        delete viewModel.allChangesObserver;
    };
};

この「グローバルオブザーバー」を使用するには:

function updateEntireViewModel() {
    var rawViewModel = Ajax_GetItemEntity(); //fetch the json object..    
    //enter validation code here, to ensure entity is correct.
    if (koGlobalObserver)
        koGlobalObserver.dispose(); //If already observing the older ViewModel, stop doing that!
    var viewModel = ko.mapping.fromJS(rawViewModel);        
    koGlobalObserver = new GlobalObserver(viewModel, Ajax_Submit);
    ko.applyBindings(viewModel [ ,optional dom element]);   
}

与えられたコールバック(この場合は 'Ajax_Submit')は、ビューモデルで発生するすべての変更で起動されることに注意してください。プロパティ:

var _entitiesUpdateTimers = {};

function Ajax_Submit(entity) { 
    var key = entity.ID; //or whatever uniquely related to the current view model..
    if (typeof _entitiesUpdateTimers[key] !== 'undefined')
        clearTimeout(_entitiesUpdateTimers[key]);    
    _entitiesUpdateTimers[key] = 
        setTimeout(function() { SendEntityFunction(entity); }, 500);           
}

私はJavaScriptとノックアウトフレームワークが初めてなので(昨日だけこの素晴らしいフレームワークを使い始めました)、何か間違ったことをしても怒ってはいけません。(-:

お役に立てれば!

2
Eitan H.S.

これは、ページが読み込まれたときにビューモデルのスナップショットを取得し、その後、そのスナップショットを現在のビューモデルと比較することで行いました。プロパティが変更された場合にのみ、どのプロパティが変更されたかは気にしませんでした。

スナップショットを撮る:

var originalViewModel = JSON.stringify(ko.toJS(viewModel));

後で比較する:

if(originalViewModel != JSON.stringify(ko.toJS(viewModel))){
    // Something has changed, but we don't know what
}
1
Sgraffite

次のようなビューモデルを検討します。

function myViewModel(){
    var that = this;
    that.Name = ko.observable();
    that.OldState = ko.observable();
    that.NewState = ko.observable();

    that.dirtyCalcultions - ko.computed(function(){
    // Code to execute when state of an observable changes.
});
}

データをバインドしたら、ko.toJS(myViewModel)関数を使用して状態を保存できます。

myViewModel.Name("test");
myViewModel.OldState(ko.toJS(myViewModel));

次のような計算されたオブザーバブルとして、ビューモデル内で変数を宣言できます。

that.dirtyCalculations = ko.computed(function () {});

この計算された関数は、ビューモデル内の他のオブザーバブルに変更がある場合に入力されます。

次に、2つのビューモデルの状態を次のように比較できます。

that.dirtyCalculations = ko.computed(function () {
  that.NewState(that);

  //Compare old state to new state
  if(that.OldState().Name == that.NewState().Name()){
       // View model states are same.
  }
  else{
      // View model states are different.
  }

});

**注:この計算された観測可能な関数は、ビューモデルが初期化されるときにも実行されます。 **

お役に立てれば !乾杯!!

1