0
votes

I've been trying to determine why the write function on a computed value would not automatically fire the mutation event at least on itself.

An example of what I'm speaking of:

<span data-bind="text: fullName"></span>
<input data-bind="value: fullName"/>

With the following JavaScript.

<script type="text/javascript">
function MyViewModel() {
    this.firstName = 'first';
    this.lastName = 'last';

    this.fullName = ko.computed({
        read: function () {
            return this.firstName + " " + this.lastName;
        },
        write: function (value) {
            var lastSpacePos = value.lastIndexOf(" ");
            if (lastSpacePos > 0) { // Ignore values with no space character
                this.firstName = value.substring(0, lastSpacePos); // Update "firstName"
                this.lastName = value.substring(lastSpacePos + 1); // Update "lastName"
            }
        },
        owner: this
    });
}

ko.applyBindings(new MyViewModel());

I understand this occurring because firstName and lastName are not observables, but I don't understand why. It would seem logical that at least any field utilizing fullName would update even if the underling data was being used individually elsewhere.

So my questions specifically are:

  1. Why is this happening?
  2. How could you get around it if you didn't want to observe firstName or lastName?

http://jsfiddle.net/TWR6Y/

1

1 Answers

4
votes

This has everything to do with how dependency tracking works.

  1. Whenever you declare a computed observable, KO immediately invokes its evaluator function to get its initial value.
  2. While your evaluator function is running, KO keeps a log of any observables (or computed observables) that your evaluator reads the value of.
  3. When your evaluator is finished, KO sets up subscriptions to each of the observables (or computed observables) that you’ve touched. The subscription callback is set to cause your evaluator to run again, looping the whole process back to step 1 (disposing of any old subscriptions that no longer apply).
  4. KO notifies any subscribers about the new value of your computed observable.

Since firstName and lastName aren't ko.observable's, KO doesn't add them to the log (see step 2). Therefor, your code (without the observables) will not work.

To further summarize the answer. Javascript at the time of this question and update, is incapable of providing event handling for native types. Knockout overcomes this issue by handling the data as to create an intercepting point for which it can see a mutation to an object. The only approach to observe natives without intercepting is to scan which is inefficient.

This problem will be overcome by Object.observe.