JSFiddle - React, Tailwind, and code Playground

by fastfasterfastest

HTML

<script src="http://bestware.us/knockout/2414-fastfasterfastest-update/knockout-latest.debug.js"></script>
<div>
  <div data-bind="if: !hasValidAddress()">
    Sorry! I don't know where you live
  </div>
  <div data-bind="ifnot: hasValidAddress">
    Echo - Sorry! I don't know where you live
  </div>
<div data-bind="if: hasValidAddress">
    You live at:
    <p data-bind="text: address.street().toUpperCase()"></p>
  </div>
  <div data-bind="ifnot: !hasValidAddress()">
    Echo - You live at:
    <p data-bind="text: address.street().toUpperCase()"></p>
  </div>
</div>
<!-- ko with: address.street(), as:'xxx' -->
    You live at:
    <p data-bind="text: address.street().toUpperCase()"></p>
<!-- /ko -->

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

<!-- ko if: true -->
<div>hasValidAddress: <span data-bind="text: hasValidAddress"></span></div>
<!-- /ko -->
<!-- ko ifnot: false -->
<div><span data-bind="text: hasValidAddress"></span></div>
<!-- /ko -->

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