http://stackoverflow.com/questions/43103439/does-a-writeable-computed-observable-really-need-an-extra-internal-observable

by jlspake

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.1/knockout-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.4.1/knockout.mapping.min.js"></script>
<h1>Writable computed observables</h1>
<p>See: <a href="http://knockoutjs.com/documentation/computed-writable.html">Knockout Doc</a></p>
<h2>Original example</h2>
<div>
  First name: <input data-bind="textInput: firstName" />
  <span data-bind="text: firstName"></span>
</div>
<div>
  Last name: <input data-bind="textInput: lastName" />
  <span data-bind="text: lastName"></span>
</div>
<div class="heading">
  Hello, <input data-bind="textInput: fullName" />
  <span data-bind="text: fullName"></span>
</div>
<h2>My example</h2>
<div>
  Name: <input data-bind="textInput: Name" />
  <span data-bind="text: Name"></span>
</div>
<div>
  Mirror first name? <input type="checkbox" data-bind="checked: cbMirror" />
  <span data-bind="text: cbMirror"></span>
</div>

JavaScript

function MyViewModel() {
  var self = this;
  // example from knockout site:
  self.firstName = ko.observable('Planet');
  self.lastName = ko.observable('Earth');

  self.fullName = ko.pureComputed({
    read: function () {
      //return;
      return self.firstName() + " " + self.lastName();
    },
    write: function (value) {
      // value is the content in the input field, visible on form,
      // but apparently not yet in the observable.
      // now copy this value to first/last-name observables,
      // that in turn copy it to the read-function,
      // that returns it to the observable.
      var lastSpacePos = value.lastIndexOf(" ");
      if (lastSpacePos > 0) { // Ignore values with no space character
        self.firstName(value.substring(0, lastSpacePos)); // Update "firstName"
        self.lastName(value.substring(lastSpacePos + 1)); // Update "lastName"
      }
    },
    owner: self
  });

  // checkbox whether or not to mirror between two fields            
  self.cbMirror = ko.observable(false);
  // this observable is to help the writable computed observable to copy input from write() to read()
  self.tmpName = ko.observable();
  // the writable computed observable that may mirror another field, depending on the checkbox
  self.Name = ko.pureComputed({
    read: function () {
      return self.cbMirror() ? self.firstName() : '';
    },
    write: function (value) {
      if (self.cbMirror()){
        self.firstName(value);
      }
    },
    owner: self
  });
}

ko.applyBindings(new MyViewModel());