Javascript 检测对 Knockout 视图模型的更改
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10622707/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Detecting change to Knockout view model
提问by user1389723
Sure this is a very easy question to answer but is there an easy way to determine if any property of a knockout view model has changed?
当然这是一个很容易回答的问题,但是有没有一种简单的方法来确定淘汰赛视图模型的任何属性是否发生了变化?
回答by Brett Green
Use extenders:
使用扩展器:
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;
};
Then:
然后:
self.MyProperty= ko.observable("Property Value").extend({ trackChange: true });
Now you can inspect like this:
现在你可以这样检查:
self.MyProperty.isDirty()
You can also write some generic viewModel traversing to see if anything's changed:
您还可以编写一些通用的 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;
}
}
});
... and then just check at the viewModel level
...然后在 viewModel 级别检查
self.isDirty()
回答by web_bod
You can subscribe to the properties that you want to monitor:
您可以订阅要监控的属性:
myViewModel.personName.subscribe(function(newValue) {
alert("The person's new name is " + newValue);
});
This will alert when personName changes.
这将在 personName 更改时发出警报。
Ok, so you want to know when anything changes in your model...
好的,所以您想知道模型中的任何更改...
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;
}
(haven't tested it - but you should get the idea)
(还没有测试过 - 但你应该明白了)
回答by dzl-pt
Consider using Knockout-Validation plug-in
It implements the following:
它实现了以下内容:
yourProperty.isModified() - Checks if the user modified the value.
yourProperty.originalValue - So you can check if the value really changed.
yourProperty.isModified() - 检查用户是否修改了值。
yourProperty.originalValue - 所以你可以检查值是否真的改变了。
Along with other validation stuff which comes in handy!
连同其他派上用场的验证内容!
Cheers
干杯
回答by Ziad
You might use the plugin below for this:
您可以使用下面的插件:
https://github.com/ZiadJ/knockoutjs-reactor
https://github.com/ZiadJ/knockoutjs-reactor
The code for example will allow you to keep track of all changes within any viewModel:
例如,代码将允许您跟踪任何视图模型中的所有更改:
ko.watch(someViewModel, { depth: -1 }, function(parents, child) {
alert('New value is: ' + child());
});
PS: As of now this will not work with subscribables nested within an array but a new version that supports it is on the way.
PS:到目前为止,这不适用于嵌套在数组中的订阅,但支持它的新版本正在开发中。
Update:The sample code was upgraded to work with v1.2b which adds support for array items and subscribable-in-subscribable properties.
更新:示例代码已升级为与 v1.2b 一起使用,它增加了对数组项和订阅中订阅属性的支持。
回答by David Freire
I've adapted @Brett Green code and extended it so that we can have AcceptChanges, marking the model as not dirty plus having a nicer way of marking models as trackables. Here is the code:
我已经修改了@Brett Green 代码并对其进行了扩展,以便我们可以使用 AcceptChanges,将模型标记为不脏,并有一种更好的方式将模型标记为可跟踪对象。这是代码:
var viewModel = {
name: ko.observable()
};
ko.track(viewModel);
回答by Eitan H.S.
I had the same problem, i needed to observe any change on the viewModel, in order to send the data back to the server, If anyone still intersted, i did some research and this is the best solution iv'e managed to assemble:
我遇到了同样的问题,我需要观察 viewModel 上的任何更改,以便将数据发送回服务器,如果有人仍然感兴趣,我做了一些研究,这是我设法组装的最佳解决方案:
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;
};
};
in order to use this 'global observer':
为了使用这个“全球观察者”:
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]);
}
Note that the callback given (in this case 'Ajax_Submit') will be fired on ANY change that occurs on the view model, so i think it's really recommended to make some sort of delay mechanism to send the entity only when the user finished to edit the properties:
请注意,给定的回调(在本例中为“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);
}
I'm new to JavaScript and the knockout framework, (only yestarday i started to work with this wonderfull framework), so don't get mad at me if i did something wrong.. (-:
我是 JavaScript 和淘汰框架的新手(直到昨天我才开始使用这个奇妙的框架),所以如果我做错了什么,请不要生我的气..(-:
Hope this helps!
希望这可以帮助!
回答by Sgraffite
I did this by taking a snapshot of the view model when the page loads, and then later comparing that snapshot to the current view model. I didn't care what properties changed, only if any changed.
我通过在页面加载时拍摄视图模型的快照,然后将该快照与当前视图模型进行比较来做到这一点。我不在乎哪些属性发生了变化,只有发生了变化。
Take a snapshot:
截图:
var originalViewModel = JSON.stringify(ko.toJS(viewModel));
Compare later:
稍后比较:
if(originalViewModel != JSON.stringify(ko.toJS(viewModel))){
// Something has changed, but we don't know what
}
回答by Sushrut Kanetkar
Consider a view model as follows
考虑如下视图模型
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.
});
}
After you Bind your Data you can store the state using ko.toJS(myViewModel) function.
绑定数据后,您可以使用 ko.toJS(myViewModel) 函数存储状态。
myViewModel.Name("test");
myViewModel.OldState(ko.toJS(myViewModel));
You can declare a variable inside your view model as a computed observable like
您可以将视图模型中的变量声明为计算出的可观察对象,例如
that.dirtyCalculations = ko.computed(function () {});
This computed function will be entered when there is change to any of the other observables inside the view model.
当视图模型中的任何其他可观察对象发生更改时,将输入此计算函数。
Then you can compare the two view model states as:
然后您可以将两个视图模型状态比较为:
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.
}
});
});
**Note: This computed observable function is also executed the first time when the view model is initialized. **
**注意:这个计算出的 observable 函数也会在视图模型初始化时第一次执行。**
Hope this helps ! Cheers!!
希望这可以帮助 !干杯!!