当任何属性更改时,knockout js 更新脏标志,使用 ko.mapping

ton*_*9uk 1 knockout.js

我正在尝试向我的淘汰赛 js 模型添加一个脏标志(我希望这是一个简单的任务),当任何属性发生更改时,该标志将更新。

我在发帖之前完成了一些研究,发现大多数答案都指向这篇博客文章,还有一个链接到该文章的小提琴,我试图遵循它,但没有成功。

我还尝试使用 jquery 来监听输入或选择元素何时发生更改,但是当填充输入时会触发页面加载,因此该标志始终会被设置为脏。

我的模型和示例之间的区别是我使用自动映射器

在示例中它显示Item有一个dirty标志。使用自动映射器时我将如何复制它?(我添加了我的 json 模型,以防它有助于提供“最佳”解决方案)

示例中的 JS

ko.dirtyFlag = function(root, isInitiallyDirty) {
var result = function() {},
    _initialState = ko.observable(ko.toJSON(root)),
    _isInitiallyDirty = ko.observable(isInitiallyDirty);

result.isDirty = ko.computed(function() {
    return _isInitiallyDirty() || _initialState() !== ko.toJSON(root);
});

result.reset = function() {
    _initialState(ko.toJSON(root));
    _isInitiallyDirty(false);
};

return result;
};

function Item(id, name) {
    this.id = ko.observable(id);
    this.name = ko.observable(name);
    this.dirtyFlag = new ko.dirtyFlag(this);
}

var ViewModel = function(items) {
this.items = ko.observableArray([
    new Item(1, "one"),
    new Item(2, "two"),
    new Item(3, "three")
]);

this.save = function() {
    alert("Sending changes to server: " + ko.toJSON(this.dirtyItems));  
};

this.dirtyItems = ko.computed(function() {
    return ko.utils.arrayFilter(this.items(), function(item) {
        return item.dirtyFlag.isDirty();
    });
}, this);

this.isDirty = ko.computed(function() {
    return this.dirtyItems().length > 0;
}, this);
};

ko.applyBindings(new ViewModel()); 
Run Code Online (Sandbox Code Playgroud)

我的 json 对象

{"PropertyID":0,"BulletPoints":["test 1","test 2","test 3"],"BriefDescription":"Some test desc","TakeOnAppointmentDate":"0017-03-02T12:05:00","Rooms":null,"TenureLengthOfLease":10,"TenureLengthOfService":10,"GroundCharges":11.0,"Directions":"go here then there","KeyHolderName":"Name","KeyHolderReference":"very nice","IsDisplayToPublic":true,"UploadToRightMove":false,"UploadToOnTheMarkert":false,"UploadToPrimeLocation":false,"RightMoveCost":1000.0,"EpcCost":100.0,"FloorPlanCost":2.0,"RoomIdentifier":null,"CoverIdentifier":null,"CoverPath":null,"PreviewUrl":null,"EpcReportPdf":null,"FloorPlan1":null,"FloorPlan2":null,"DisplayFrom":185.000,"DisplayTo":200.000,"SelectedSalePriceOptionId":3,"IsHidden":null,"AddressLine1":null,"NumberOfBedrooms":5,"NumberOfBathrooms":3,"NumberOfReceptionrooms":2,"Tenures":[{"Id":1,"Description":"Freehold"},{"Id":2,"Description":"LeaseHold"}],"SelectedTenureId":2,"ViewingInstructions":[{"Id":1,"Description":"Accompanied viewings with prior notice"},{"Id":2,"Description":"Vacant property"},{"Id":3,"Description":"Vendor to do viewings"}],"SelectedViewingInstructionId":2,"SaleStates":[{"Id":1,"Description":"For Sale"},{"Id":2,"Description":"Sold"},{"Id":3,"Description":"SSTC"},{"Id":4,"Description":"To Let"}],"SelectedSaleStateId":2,"UnderOffers":[{"Id":0,"Description":"No"},{"Id":1,"Description":"Yes"}],"SelectedUnderOfferId":1,"SalePriceOptions":[{"Id":1,"Description":"Asking Price"},{"Id":2,"Description":"Guide Price"},{"Id":3,"Description":"Offers Over"},{"Id":4,"Description":"In the region of"},{"Id":5,"Description":"Auction guide"}],"BlobItems":[]}
Run Code Online (Sandbox Code Playgroud)

Jas*_*ake 5

在最基本的实现中,全局脏标志所需的只是三件事

  • 用于保存脏状态的状态变量(布尔标志)
  • 在根对象上使用 ko.toJS 或 ko.toJSON 的计算属性
  • 订阅函数,用于在计算属性更改时更新状态变量

如果您的视图模型是使用 ko.mapping 构建的,它可能看起来像这样:

var viewModel = function(jsonData){
  var self = this;

  ko.mapping.fromJS(jsonData, {}, this);

  self.isDirty = ko.observable(false);
  self.toJS = ko.computed(function(){
    return ko.toJS(self);
  });
  self.toJS.subscribe(function(value){
    self.isDirty(true);
  });
}
Run Code Online (Sandbox Code Playgroud)

jsFiddle

之后,您可以添加额外的复杂性来存储初始 toJS() 结果并将其与新值进行比较,以查看数据是否确实已更改或者是否只是设置回相同的数据。

正如该博客继续说的那样,这不是最好的方法。任何更改都会导致计算通过遍历视图模型中的整个可观察树来重新计算,这可能会导致昂贵的代价。

这是我使用了一段时间的另一个版本,它仅在第一次进行更改时进行评估,然后仅返回 dirty=true 。我很确定我也从 Ryan Niemeyer 那里得到了这个,但我不记得在哪里。我在您引用的博客上没有看到类似的内容。

var viewModel = function(jsonData){
  var self = this;

  ko.mapping.fromJS(jsonData, {}, this);

  this.dirtyCheck = ko.computed({
    read: function() {
      if (!self.isDirty){ //property doesn't exist yet
        var json = ko.toJSON(self); //trigger a subscription to all observable properties.
      } else {
        self.isDirty(true); //If this is being evaluated then by definition something has changed.
      }
      return;
    }
  });
  this.isDirty = ko.observable(false); //only add the property after the computed has been initialized
}
Run Code Online (Sandbox Code Playgroud)