JSFiddle - React, Tailwind, and code Playground

by Ebram

HTML

<script src="//cdnjs.cloudflare.com/ajax/libs/knockout/2.2.1/knockout-min.js"></script>
<input data-bind="value: name" />
<input data-bind="value: quantity" />
<button data-bind="click: commitAll">Commit</button>
<button data-bind="click: resetAll">Reset</button>

JavaScript

//wrapper to an observable that requires accept/cancel
ko.protectedObservable = function (initialValue) {
    //private variables
    var _actualValue = ko.observable(initialValue),
        _tempValue = initialValue;

    //computed observable that we will return
    var result = ko.computed({
        //always return the actual value
        read: function () {
            return _actualValue();
        },
        //stored in a temporary spot until commit
        write: function (newValue) {
            alert('call write');
            _tempValue = newValue;
        }
    });

    //if different, commit temp value
    result.commit = function () {
        if (_tempValue !== _actualValue()) {
            _actualValue(_tempValue);
        }
    };

    //force subscribers to take original
    result.reset = function () {
        _actualValue.valueHasMutated();
        _tempValue = _actualValue(); //reset temp value
    };

    return result;
};
var viewModel = {
    name: ko.protectedObservable("Item A"),
    quantity: ko.protectedObservable(10),
    commitAll: function () {
        this.name.commit();
        this.quantity.commit();
    },
    resetAll: function () {
        this.name.reset();
        this.quantity.reset();
    }
};
ko.applyBindings(viewModel);