【问题标题】:Knockout JS autosave ratelimit淘汰赛JS自动保存速率限制
【发布时间】:2021-03-08 15:29:16
【问题描述】:

这是一个小提琴https://jsfiddle.net/pqs142aw/

我想在用户停止更改时自动保存。我遇到的问题是对 ko.computedContext.isInitial() 的检查仅在初始页面加载期间发生,并且在对可观察对象进行更改后不会触发。

ko.computed(function () {
    var isInitial = ko.computedContext.isInitial();               
    if (isInitial) {
        console.log("init...");                         
    }
    else { 
       //doesn't get called
       console.log("saving...");            
       self.save(); 

    }}, self).extend({ rateLimit: { timeout: 1000, method: "notifyWhenChangesStop" } });

我怎样才能让它工作或有更好的方法?

【问题讨论】:

  • 更新了小提琴 jsfiddle.net/pqs142aw/1>。这将在更改停止后自动保存,但它也会在我不想要的初始页面加载时触发。

标签: knockout.js


【解决方案1】:

我更改了一些内容来演示如何使这项工作:

  • 添加了一些输入、一个计算值和一个常数,以显示它的扩展方式。
  • viewModel 计算值更改为返回整个对象的 json 字符串,除了这个 viewModel 计算值。例程 ko.JS 循环遍历所有可观察对象,因此从现在开始,当任何可观察对象发生变化时,都会触发计算。
  • 向此计算添加订阅以在触发计算时调用保存。

看看下面的例子:

var ViewModel = function() {
  var self = this;
  self.id = 1234;
  self.firstname = ko.observable();
  self.prefix = ko.observable();
  self.lastname = ko.observable();
  self.fullname = ko.computed(function() {
    return `${self.firstname() || ''} ${self.prefix() || ''} ${self.lastname() || ''}`
  });

  self.save = function(json) {
    console.log(`saved... ${json}`);
  };

  self.viewModel = ko.computed(function() {
    var vm = ko.toJS(self);
    delete vm.viewModel;
    return JSON.stringify(vm);
  }).extend({ rateLimit: { timeout: 1000, method: "notifyWhenChangesStop" } });

  self.viewModel.subscribe(function(json) {
    self.save(json);
  });
};

ko.applyBindings(new ViewModel());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<p>Id: <span data-bind='text: id'></span></p>
<p>Firstname: <input data-bind='textInput: firstname' /></p>
<p>Firstname: <input data-bind='textInput: prefix' /></p>
<p>Lastname: <input data-bind='textInput: lastname' /></p>
<p>Fullname: <span data-bind='text: fullname'></span></p>

【讨论】:

  • 感谢感谢您的回复。所以我需要在计算中指定所有需要保存的 observables/properties?例如,如果我有一个包含 25 个以上输入的表单,我需要指定所有这些吗?有没有更有效的方法来做到这一点?
  • 你是对的。这并没有很好地扩展。我用一个包含额外输入、计算和常量的新示例更新了答案。
【解决方案2】:

我得到了这个为我工作的更新小提琴https://jsfiddle.net/qLu6jnmy/

    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;
    };

var ViewModel = function () {
            var self = this;                        
            self.firstName = ko.observable();
            self.middleName = ko.observable();
            self.lastName = ko.observable();
            self.dirtyFlag = new ko.dirtyFlag(self);           

            self.save = function () {
                const viewModelToJson = ko.toJSON(self); 
                console.log("saved...");                    
            };
 
            ko.computed(function () {
                if (self.dirtyFlag.isDirty()) {
                    self.save();
                    self.dirtyFlag.reset();
                }
            }).extend({ rateLimit: { timeout: 1000, method: "notifyWhenChangesStop" } });
        };
        
        var vm = new ViewModel();            
        ko.applyBindings(vm); 

这篇文章http://www.knockmeout.net/2011/05/creating-smart-dirty-flag-in-knockoutjs.html 中的一个关键部分解释了如何实现一个通用的脏标志。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-13
    • 2013-08-14
    • 1970-01-01
    • 2013-02-12
    相关资源
    最近更新 更多