JSFiddle - React, Tailwind, and code Playground

by fastfasterfastest

HTML

<script src="http://bestware.us/knockout/3.5.0-pre-20170420/knockout-latest.debug.js"></script>
<div>
  <div data-bind="ifnot: hasValidAddress">
    Sorry! I don't know where you live
  </div>

  <div data-bind="if: hasValidAddress">
    You live at:
    <p data-bind="text: '' + address.streetNumber() + ' ' + address.street().toUpperCase()"></p>
  </div>
</div>

<button data-bind="click: function() { address({ street: 'My Street', streetNumber: 123 }); }">Set Address</button>
<button data-bind="click: function() { address(null); }">Clear Address</button>

CSS

div {
  border: 1px solid gray;
  padding: .5em;
  margin: .5em;
}

div > div
{
  border: 1px solid lightgray;
}
button {
  display: inline-block;
  margin-left: 1em;
}

JavaScript

function observableAddress(street, streetNumber) {
    var observableStreet = ko.observable(street),
        observableStreetNumber = ko.observable(streetNumber),
        result = ko.pureComputed({
            read: function () {
                return {
                    street: observableStreet(),
                    streetNumber: observableStreetNumber()
                };
            },
            write: function (newValue) {
                observableStreet(newValue ? newValue.street : null);
                observableStreetNumber(newValue ? newValue.streetNumber : null);
            }
        }).extend({ deferred: true });

    result.street = observableStreet;
    result.streetNumber = observableStreetNumber;

    return result;
}

function ViewModel() {
    this.address = observableAddress();

    this.hasValidAddress = ko.pureComputed(function () {
        var address = this.address();

        return address && (typeof address.street === "string") && (typeof address.streetNumber === "number");
    }, this);

}

ko.options.deferUpdates = true;
ko.onError = function (error) {
    alert("knockout error\n" + error);
};

// bind viewmodel
var vm = new ViewModel();
ko.applyBindings(vm);