From b720bf03af665b54e09cf21714992b85d02d9d61 Mon Sep 17 00:00:00 2001 From: chrisala Date: Thu, 22 Feb 2024 14:01:27 +1100 Subject: [PATCH] Support control of trailing zeros #236 --- .../assets/javascripts/knockout-utils.js | 31 ++++++++++++++----- .../ala/ecodata/forms/ModelJSTagLib.groovy | 6 +++- 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/grails-app/assets/javascripts/knockout-utils.js b/grails-app/assets/javascripts/knockout-utils.js index 7e09a50..d4f9397 100644 --- a/grails-app/assets/javascripts/knockout-utils.js +++ b/grails-app/assets/javascripts/knockout-utils.js @@ -164,7 +164,22 @@ * @param precision the number of decimal places allowed. * @returns {Computed} */ - ko.extenders.numericString = function(target, precision) { + ko.extenders.numericString = function(target, options) { + var defaults = { + decimalPlaces: 2, + removeTrailingZeros: true // backwards compatibility + }; + if (_.isNumber(options)) { + options = {decimalPlaces: options}; + } + options = _.extend({}, defaults, options); + + function roundAndToString(value) { + var roundingMultiplier = Math.pow(10, options.decimalPlaces); + var roundedValue = Math.round(value * roundingMultiplier) / roundingMultiplier; + return roundedValue.toString(); + } + //create a writable computed observable to intercept writes to our observable var result = ko.computed({ read: target, //always return the original observables value @@ -173,18 +188,18 @@ if (typeof val === 'string') { val = newValue.replace(/,|\$/g, ''); } - var current = target(), - roundingMultiplier = Math.pow(10, precision), - newValueAsNum = isNaN(val) ? 0 : parseFloat(+val), - valueToWrite = Math.round(newValueAsNum * roundingMultiplier) / roundingMultiplier; + var current = target(); + var newValueAsNum = isNaN(val) ? 0 : parseFloat(+val); + + var valueToWrite = options.removeTrailingZeros ? roundAndToString(newValueAsNum) : newValueAsNum.toFixed(options.decimalPlaces); //only write if it changed - if (valueToWrite.toString() !== current || isNaN(val)) { - target(isNaN(val) ? newValue : valueToWrite.toString()); + if (valueToWrite !== current || isNaN(val)) { + target(isNaN(val) ? newValue : valueToWrite); } else { if (newValue !== current) { - target.notifySubscribers(valueToWrite.toString()); + target.notifySubscribers(valueToWrite); } } } diff --git a/grails-app/taglib/au/org/ala/ecodata/forms/ModelJSTagLib.groovy b/grails-app/taglib/au/org/ala/ecodata/forms/ModelJSTagLib.groovy index b186dde..52ea12a 100644 --- a/grails-app/taglib/au/org/ala/ecodata/forms/ModelJSTagLib.groovy +++ b/grails-app/taglib/au/org/ala/ecodata/forms/ModelJSTagLib.groovy @@ -624,7 +624,11 @@ class ModelJSTagLib { def numberViewModel(JSModelRenderContext ctx) { int decimalPlaces = ctx.dataModel.decimalPlaces ?: 2 - observable(ctx, ["{numericString:${decimalPlaces}}"]) + + Map options = new HashMap(ctx.viewModel()?.displayOptions ?: [:]) + options.decimalPlaces = decimalPlaces + String optionString = (options as JSON).toString() + observable(ctx, ["{numericString:${optionString}}"]) } def dateViewModel(JSModelRenderContext ctx) {