0
self.totalHours = ko.pureComputed(function() {
        var start=self.num1;
        var end=self.num2;
        return start+end; 
});

<input   type="text" data-bind="textInput: start">
<input  type="text" data-bind="textInput: end">
<input  type="text" data-bind='text: totalHours()'>

The above first is part of my viewmodel and the second is part of my model. num1,num2 are observables. Every time I change manually the value inside the above first two inputs the third input is updated immediately; however, when the values change by code, knockout does not listen to the changes and total is not updated. How may I oblige knockout to listen to the changes provoked by code?

Unknown developer
  • 5,414
  • 13
  • 52
  • 100
  • How are you changing the values by code, give an example. If you are just accessing the model and changing the value there... it wont budge, knockout reforms the object on `applyBinding` and uses it's own structure. – Dellirium Aug 17 '16 at 11:14
  • 1
    Possibly this? http://stackoverflow.com/questions/7018885/knockout-js-bound-input-value-not-updated-when-i-use-jquery-valxyz – Roy J Aug 17 '16 at 13:14
  • Thanks Roy J. That solved my problem! – Unknown developer Aug 17 '16 at 14:09

2 Answers2

1

Quite some stuff you can fix and improve here:

  • A computed value will re-evaluate when an observable it uses in its method changes: self.num1 and/or self.num2 need to be observable and evaluated using ()
  • If you want to bind an <input>'s value, you have to use either the value or textInput data-bind; the text bind will not work.
  • If you want to write to a computed, you'll have to specify a write method. You'll have to tell knockout how to update the computed's dependencies to make sure all values add up. (e.g.: setting totalHours could set num1 to totalHours and num2 to 0)
  • You've bound to start and end, while your viewmodel properties are named num1 and num2.
  • When using value or textInput, user input will be returned as a string. You'll need to parse the strings to numbers if you want to use them in any math.

Now that all code should be working correctly, you can update your viewmodel's values via the inputs, or via code:

var ViewModel = function() {
  var self = this;
  
  self.num1 = ko.observable(0);
  self.num2 = ko.observable(0);
  
  self.totalHours = ko.pureComputed(function() {
    var start = parseFloat(self.num1());
    var end = parseFloat(self.num2());
    return start + end;
  });
  
};

var vm = new ViewModel();

ko.applyBindings(vm);

// Updating your values from code:
vm.num1(1);
vm.num2(2);

// Whenever the values need to be updated via js,
// you should change the source values, _not_ the
// <input>'s values. Worst case scenario, you'll
// have to do something like this:

var updateNum1ViaDOM = function() {
  ko.dataFor(document.querySelector("input")).num1(5);
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<input type="text" data-bind="textInput: num1">
<input type="text" data-bind="textInput: num2">
<span data-bind='text: totalHours'></span>

Note: it's probably better to use an extender to force num1 and num2 to be numeric: Live Example 1: Forcing input to be numeric

user3297291
  • 22,592
  • 4
  • 29
  • 45
  • However, you say nothing about my question! In case num1 or num2 are changed by code, the text inside the span will not be updated automatically. It is updated only if I change the values manually... – Unknown developer Aug 17 '16 at 13:17
  • When you fix the errors, there should be no differences between updating an observable from code (e.g.: `self.num1(12)`) or via the input fields. When you want to change the values, you should change the viewmodel properties, not change the DOM elements' attributes. How are you "changing the values by code"? – user3297291 Aug 17 '16 at 13:37
0

Not sure if it is a copy paste problem but the the code you posted will not work as intended. I've updated the example, when changing an observable value it must be passed as parameter so as not to overwrite the knockout observable

self.start = ko.observable();
self.end = ko.observable();

self.totalHours = ko.computed(function() {
    return self.start() + self.end();
});

<input   type="text" data-bind="textInput: start">
<input  type="text" data-bind="textInput: end">
<input  type="text" data-bind='text: totalHours()'>

//Then when changing the value by code
var newValue = 42;
model.start(newValue); //assuming you are making the change outside your viewmodel

*Just noticed this code will throw an exception when you edit the input bound to totalHours as it does not have a write handler defined. This is a separate issue though.

Rob M.
  • 11
  • 3