user2744722 - 6 months ago 41

Javascript Question

this might be easiest to describe with a fiddle http://jsfiddle.net/LkqTU/32190/

I have an observable called price which has an extender so that it rounds to two digits and does not allow non numeric.

I have a writable computed observable that puts a dollar sign in front of it.

however if the extender returns 0. the second time it happens $0 is not returned to the textbox (the computed observable) so if I type hello world in the textbox (computed observable) the price correctly reports 0 and the formatted price shows $0. however if I clear it out and type in hello world a second time. this time price is still $0 but the formatted price textbox is showing hello world (even though formatted price is reporting $0). must be missing a notification somewhere?

here is the code.

`ko.extenders.numeric = function(target, precision) {`

//create a writable computed observable to intercept writes to our observable

var result = ko.pureComputed({

read: target, //always return the original observables value

write: function(newValue) {

var current = target(),

roundingMultiplier = Math.pow(10, precision),

newValueAsNum = isNaN(newValue) ? 0 : parseFloat(+newValue),

valueToWrite = Math.round(newValueAsNum * roundingMultiplier) / roundingMultiplier;

//only write if it changed

if (valueToWrite !== current) {

target(valueToWrite);

} else {

//if the rounded value is the same, but a different value was written, force a notification for the current field

if (newValue !== current) {

target.notifySubscribers(valueToWrite);

}

}

}

}).extend({

notify: 'always'

});

//initialize with current value to make sure it is rounded appropriately

result(target());

//return the new computed observable

return result;

};

function model() {

var self = this;

this.price = ko.observable('29.01').extend({

numeric: '2'

});

this.formattedPrice = ko.computed({

read: function() {

return '$' + this.price()

},

write: function(value) {

value = parseFloat(value.replace(/[^\.\d]/g, ""));

this.price(isNaN(value) ? 0 : value);

},

owner: this

});

}

var mymodel = new model();

$(document).ready(function() {

ko.applyBindings(mymodel);

});

Answer

What seemed to work for me was extending the `formattedPrice`

computed variable to always notify and modify the write method to just pass in the value rather than checking for isNaN; your extender does this anyway and forcing a 0 makes it so that your `if (newValue !== current)`

test never returns true as newValue and current will always be 0 in this scenario (NaN !== 0 *will* pass the check):

```
this.formattedPrice = ko.computed({
read: function() {
return '$' + this.price()
},
write: function(value) {
value = parseFloat(value.replace(/[^\.\d]/g, ""));
this.price(value); //just pass in nan or the value so the extender can check/notify if newValue !== current
},
owner: this
}).extend({
notify: 'always'
});
```

Updated fiddle: http://jsfiddle.net/LkqTU/32192/