JSFiddle - React, Tailwind, and code Playground

by nyothecat

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.1/knockout-min.js"></script>
<button data-bind='click: updateValue'>Update</button>
<button data-bind='click: revertValue'>Revert</button>
<p data-bind='text: someValue().version'></p>

JavaScript

ko.extenders.keepHistory = function(target, option) {
    target.subscribe(function(newValue) {
       if (target.reverting) { target.reverting = false; return; }
       if(!target.history) target.history = ko.observableArray();
       if(!target.revert) {
           target.revert = function () {
           console.log(target.history()[target.history().length -3]);
           		var previousVersion = target.history().length < 2 ? null : target.history()[target.history().length -2];
              if (!!previousVersion) {
                  target.reverting = true;
                  console.log(previousVersion);
                  target(previousVersion);
              }
           }
       }
       target.history.push(newValue);
       console.log(target.history());
    });
    return target;
};

var vm1 = function (name) {
    this.name = name;
    this.version = 0;
    this.toLogString = function () {
        return name;
    }
}

var vm = function () {
    var self = this;
    this.someValue = ko.observable(new vm1("My vm1")).extend({keepHistory: true});
    this.updateValue = function () {
        var clone = Object.assign({}, self.someValue());
        clone.version++;
        self.someValue(clone);
    }
    this.revertValue = function () {
        if (typeof self.someValue.revert == 'function') 
            self.someValue.revert();
    }
}

var vmi = new vm();

ko.applyBindings(vmi);