Knockoutjs does not update the user interface in this case

I am relatively new to KO (started 2 days ago) and tried some simple examples. I am currently having a problem with this piece of code.

<div id="idChangeStyle"> <span data-bind="style: { background: GetAge() < 18 ? 'red':'white'}">Enter Your Age:</span> <input type="text" data-bind="value: GetAge"></input> </div> 
 function ageViewModel() { var self = this; self.age = ko.observable(18); self.GetAge = ko.computed({ read: function () { return self.age(); }, write: function (value) { value = parseInt(String(value).replace(/[^\d]/g, "")); if (isNaN(value)) self.age(18); else self.age(value); } }); }; ko.applyBindings(new ageViewModel(), document.getElementById('idChangeStyle')); 

http://jsfiddle.net/WJZqj/

Basically the application accepts one input (age). I use writeable records for parsing input in INTEGER and after parsing, if its NaN I try to set the default value for age to 18. That is, I have a simple logic in html where I change the span background to red, if age is less than 18.

In the normal case, it works fine, that’s when I get into the problem: -

 Case 1: Current Input: 18 (initial case) enter *4* then tab //works enter *a* then tab //work (defaults to 18) enter *a* then tab //doesn't work case 2: current input: 18 enter *a *then tab* //*doesn't work 

I checked the knockout code to find out what happens when the following code fragment starts: -

 if(isNaN(value)) self.age(18); 

.. in the next line: -

 // Ignore writes if the value hasn't changed if ((!observable['equalityComparer']) || !observable['equalityComparer'](_latestValue, arguments[0])) { 

both _latestValue and arguments[0] have the same value (18), so they do nothing. Due to the absence of a change in the age value, now the viewmodel property and user interface are not synchronized.

Is it because I'm doing it wrong?

+4
source share
3 answers

The problem is that if you enter the same value for the observed, it does not consider it a change in value and does not notify subscribers. If you entered the error state several times in a row, 18 would be the set age first and set again, no changes will occur.

With that said, to fix this, you must notify subscribers manually. You can simply do this by calling valueHasMutated() on the observable.

 self.GetAge = ko.computed({ read: function () { return self.age(); }, write: function (value) { value = parseInt(String(value).replace(/[^\d]/g, "")); if (isNaN(value)) self.age(18); else self.age(value); self.age.valueHasMutated(); // notify subscribers } }); 
+1
source

I have the same situation when I use knockout 3.0. . But these tricks do not help me, because now the knockout notifies only when the calculated property values ​​change .

And I will fix the problem: 1) use only notification: always

 function ageViewModel(data) { //notify will should be always, because age is a primitive type this.age = ko.observable(data.age).extend({notify: "always"}); this.GetAge = ko.computed({ read: function () { // notify will should be always, because computed return values of a primitive type. return this.age(); }, write: function (value) { value = parseInt(String(value).replace(/[^\d]/g, "")); if (isNaN(value)) { this.age(18); } else this.age(value); }, owner: this }).extend({notify: "always"}); }; 

2) use notification: always and knockout.mapping

 function ageViewModel(data) { ko.mapping.fromJS(data, {}, this); //notify will should be always, because age is a primitive type this.age = this.age.extend({notify: "always"}); this.GetAge = ko.computed({ read: function () { // notify will should be always, because computed return values of a primitive type. return this.age(); }, write: function (value) { value = parseInt(String(value).replace(/[^\d]/g, "")); if (isNaN(value)) { this.age(18); } else this.age(value); }, owner: this }).extend({notify: "always"}); }; 
+2
source

An easy way around this is to set the age to 0, and then return to the default.

ie, change to:

 if(isNaN(value)) { self.age(0); self.age(18); } 

I don’t know which knockout I would consider “right”, but it’s possible that I will do it.

0
source

All Articles