1
votes

I have created a computed observable from simple observables like this:

  • this.fullDetails is the computed observable.
  • this.computeFullDetails is the computed's read function.
  • this.writeToComponents is the computed's write function.

When i modify the input box corresponding to the atomic observables the computed properties get modified but when i modify the computed properties,the atomic ones are not updated. Can I get an alternative approach to get something like this done?.

please see this fiddle http://jsfiddle.net/saurabh0jha/wqpZ9/

function PersonViewModel()
{
    this.firstName = ko.observable("");
    this.lastName = ko.observable("");
    this.phoneNos = ko.observable(0);
    this.address = ko.observable("");
    this.computeFullDetails = function(){
            retObj = {};
            retObj.firstName=ko.observable(this.firstName());
            retObj.lastName=ko.observable(this.lastName());
            retObj.phoneNos=ko.observable(this.phoneNos());
            retObj.address=ko.observable(this.address());
            return retObj; 
        };
    
    this.writeToComponents = function(value){
                this.firstName(value.firstName());
                this.lastName(value.lastName());
                this.phoneNos(value.phoneNos());
                this.address(value.address());
            };
        
    this.fullDetails = ko.computed(
        {
            read:this.computeFullDetails,
            write:this.writeToComponents,
        },this);

}


var vm = new PersonViewModel();
ko.applyBindings(vm);

HTML

<html lang='en'>
<head>
  <title>Hello, Knockout.js</title>
  <meta charset='utf-8' />
  <link rel='stylesheet' href='style.css' />
</head>
<body>
    <h2>atomic</h2>
    <input data-bind="value: firstName" style="display:block" />
    <input data-bind="value: lastName" style="display:block"/>
    <input data-bind="value: phoneNos"style="display:block" />
    <input data-bind="value: address" style="display:block"/>
    <h2>computed</h2>
    <input data-bind="value: fullDetails().firstName" style="display:block"/>
    <input data-bind="value:fullDetails().lastName" style="display:block"/>
    <input data-bind="value: fullDetails().phoneNos"style="display:block" />
    <input data-bind="value: fullDetails().address"style="display:block" />

    <script type='text/javascript' src='knockout-2.2.0.js'></script>
    <script type='text/javascript' src='2computedObservables.js'>   </script>
</body>
</html>
2
Please note that the bindings to the properties of fullDetails() such as fullDetails().firstName don't actually cause writeToComponents to fire when the textbox value changes. - David Tansey
That is my exact problem here .The same write back will work if the computed is calculated using string operations like this return self.firstName+ " " +self.lastName. But when i want to write back to observables nested in object,it does not work.Dont know if there is a simple way to do it as i am not comfortable writing custom bindings. - saurabhOjha

2 Answers

0
votes

Not sure what you are trying to do.

The problem with your code is that you do not subscribe to the observables you return in computeFullDetails.

You can try this:

<input data-bind="value: fullDetailsFirstName" style="display:block" />

this.fullDetailsFirstName = ko.computed({
    read: function () {
        return self.firstName();
    },
    write: function (newValue) {
        self.firstName(newValue)
    }
});

Example (changed only firstName): http://jsfiddle.net/nyothecat/VJ4th/1/

0
votes

This:

retObj.firstName=ko.observable(this.firstName());

creates a new observable with the value of the old one. Because of this, you lose all the old dependencies every time computeFullDetails is called.

Everything that was bound to a previous fullDetails().firstName will never be updated again.

If I understand you correctly, you want something like this:

function PersonViewModel() {
    this.firstName = ko.observable("");
    this.lastName  = ko.observable("");
    this.phoneNos  = ko.observable(0);
    this.address   = ko.observable("");

    this.anyAttribute = ko.computed(function() {
      this.firstName();
      this.lastName();
      this.phoneNos();
      this.address();

      // what this returns is not important, its
      // only job is to notify subscribers when any
      // dependency has changed
    });

    this.anyAttribute.subscribe(function() {
      // do here whatever you need to do when any
      // of the attributes has changed
    });
}

var vm = new PersonViewModel();
ko.applyBindings(vm);