KnockoutJS中数字的格式规则

时间:2011-10-09 14:39:53

标签: knockout.js

我有一个带有大量小数位数的viewModel。如果我的绑定看起来像这样:

    <tr>
        <td data-bind="text: Date"></td>
        <td data-bind="text: ActualWeight"></td>
        <td data-bind="text: TrendWeight"></td>
    </tr>

然后,当然,输出具有所有小数位并且非常不可读。将绑定更改为这样可以解决问题,但是非常冗长且“嘈杂”:

    <tr>
        <td data-bind="text: Date"></td>
        <td data-bind="text: ActualWeight().toFixed(1)"></td>
        <td data-bind="text: TrendWeight().toFixed(1)"></td>
    </tr>

注意,这是一个小片段,必须添加.toFixed(1)我绑定一个数字的每个地方都会导致比这里显示的更加混乱的标记。

对于除数字之外的所有内容,覆盖toString一直是我控制输出内容的有效方法。有关告诉敲门的方法的任何建议,在我的页面的某些中心方式中,在将数字添加到输出之前将数字转换为字符串的功能是什么?

就此而言,有一个通用的方法告诉淘汰赛如何格式化任何类型的值似乎是有用的。重写Date.prototype.toString可以工作,但感觉有点沉重,因为它可能会影响.toString的其他用途除了敲击之外。

6 个答案:

答案 0 :(得分:94)

有几种方法可以处理像这样的情况。您可以选择通过绑定来解决它,也可以将其推送到视图模型中。

如果您的视图模型是由映射插件创建的,并且您不想自定义它的创建方式,那么您可以考虑使用自定义绑定作为文本绑定的包装来处理格式

像(http://jsfiddle.net/rniemeyer/RVL6q/):

ko.bindingHandlers.numericText = {
    update: function(element, valueAccessor, allBindingsAccessor) {
       var value = ko.utils.unwrapObservable(valueAccessor()),
           precision = ko.utils.unwrapObservable(allBindingsAccessor().precision) || ko.bindingHandlers.numericText.defaultPrecision,
           formattedValue = value.toFixed(precision);

        ko.bindingHandlers.text.update(element, function() { return formattedValue; });
    },
    defaultPrecision: 1  
};

当然可以创建一个更通用的绑定(formattedText),它检查值并使用一些可覆盖的默认值对其进行格式化,或者允许您传递一些格式选项({ type: "numeric", precision: 2 })。

对于您的场景,听起来第一个选项可能是一个不错的选择。但是,如果要将其推入视图模型,则可以创建一个特殊的observable,它可以返回值的格式化和原始版本。

可能类似于(http://jsfiddle.net/rniemeyer/fetBG/):

function formattedNumericObservable(initialValue, precision) {
    var _raw = ko.observable(initialValue),
        precision = precision || formattedNumericObservable.defaultPrecision,        
        //the dependentObservable that we will return
        result = ko.dependentObservable({
            read: function() {
               return _raw().toFixed(precision); 
            },
            write: _raw
        });

        //expose raw value for binding
        result.raw = _raw;

        return result;   
}

现在,您可以根据需要绑定myValuemyValue.raw。否则,您可以将其翻转并默认返回原始值并公开formatted dependentObservable。当像这样的对象转换为JSON时,它将丢失任何“子可观察量”,因此如果您将此数据发送回可能需要考虑的服务器。

您可以再次使其更通用,并创建一个formattedObservable,其中包含有关如何格式化对象的一些信息。

最后,1.3 beta提供了extenders API。你可以做类似上面的事情:(http://jsfiddle.net/rniemeyer/AsdES/

ko.extenders.numeric = function(target, precision) {
    var result = ko.dependentObservable({
        read: function() {
           return target().toFixed(precision); 
        },
        write: target 
    });

    result.raw = target;
    return result;
};

然后,将其应用于如var myValue = ko.observable(1.223123).extend({numeric: 1});

之类的可观察对象

您可以让扩展程序只将formatted dependentObservable添加到target,而不是返回dependentObservable本身。

答案 1 :(得分:22)

由于knockout现在支持extenders,我会使用它们而不是自定义绑定。绑定看起来像这样:

<tr>
    <td data-bind="text: Date.extend({format : 'date'})"></td>
    <td data-bind="text: ActualWeight.extend({format : 'weight'})"></td>
    <td data-bind="text: TrendWeight.extend({format : 'weight'})"></td>
</tr>

在这种情况下,您必须编写format扩展程序。淘汰文档中提供了示例。

答案 2 :(得分:10)

要格式化货币和百分比,我创建了自定义绑定数字格式.js,用于http://adamwdraper.github.com/Numeral-js/

处的numeral.min.js

numeralformat.js(灵感来自dateformat.js和moment.min.js)

var formatNumber = function (element, valueAccessor, allBindingsAccessor, format) {
    // Provide a custom text value
    var value = valueAccessor(), allBindings = allBindingsAccessor();
    var numeralFormat = allBindingsAccessor.numeralFormat || format;
    var strNumber = ko.utils.unwrapObservable(value);
    if (strNumber) {
        return numeral(strNumber).format(numeralFormat);
    }
    return '';
};

ko.bindingHandlers.numeraltext = {
    init: function (element, valueAccessor, allBindingsAccessor) {
        $(element).text(formatNumber(element, valueAccessor, allBindingsAccessor, "(0,0.00)"));  
    },
    update: function (element, valueAccessor, allBindingsAccessor) {
        $(element).text(formatNumber(element, valueAccessor, allBindingsAccessor, "(0,0.00)"));
    }
};

ko.bindingHandlers.numeralvalue = {
    init: function (element, valueAccessor, allBindingsAccessor) {
        $(element).val(formatNumber(element, valueAccessor, allBindingsAccessor, "(0,0.00)"));

        //handle the field changing
        ko.utils.registerEventHandler(element, "change", function () {
            var observable = valueAccessor();
            observable($(element).val());
        });        
    },
    update: function (element, valueAccessor, allBindingsAccessor) {
        $(element).val(formatNumber(element, valueAccessor, allBindingsAccessor, "(0,0.00)"));
    }
};

ko.bindingHandlers.percenttext = {
    init: function (element, valueAccessor, allBindingsAccessor) {
        $(element).text(formatNumber(element, valueAccessor, allBindingsAccessor, "(0.000 %)"));
    },
    update: function (element, valueAccessor, allBindingsAccessor) {
        $(element).text(formatNumber(element, valueAccessor, allBindingsAccessor, "(0.000 %)"));
    }
};

ko.bindingHandlers.percentvalue = {
    init: function (element, valueAccessor, allBindingsAccessor) {
        $(element).val(formatNumber(element, valueAccessor, allBindingsAccessor, "(0.000 %)"));

        //handle the field changing
        ko.utils.registerEventHandler(element, "change", function () {
            var observable = valueAccessor();
            observable($(element).val());
        });
    },
    update: function (element, valueAccessor, allBindingsAccessor) {
        $(element).val(formatNumber(element, valueAccessor, allBindingsAccessor, "(0.000 %)"));
    }
};

View中的绑定示例。

        <td><label>Available Commitment Balance:</label> </td>
        <td>
            <!-- ko with: SelectedLoan -->
            <span data-bind="numeraltext: AvailableCommitmentAmount"></span>            
            <!-- /ko -->
        </td>
        <td><label> % Interest Rate:</label></td>
        <td>
            <!-- ko with: SelectedLoan -->
            <input  data-bind="percentvalue: InterestRatePercent" />
            <!-- /ko -->
        </td>
        <td><label> $ Amount To Transfer:</label></td>
        <td>
            <!-- ko with: SelectedLoan -->
            <input class="inputsmall" data-bind="numeralvalue: FundsHeldTotalAmount" />
            <!-- /ko -->
        </td>

答案 3 :(得分:9)

建立在上面接受的答案之上。我分叉RP Niemeyers小提琴添加逗号格式。 所以,如果你有10001.232,这将格式化为10,001.232。如果您正在处理价格,这非常重要。同样,这只是建立在答案之上。

JSFiddle

<div data-bind="numericText: myValue"></div>
<div data-bind="numericText: myValue, positions: 3"></div>
<div data-bind="numericText: myValue, positions: myPositions"></div>
<input data-bind="value: myPositions" />

<div>
    <br>
    just testing commas<br>
    <input type=text id="withComma" readonly/>
</div>
ko.bindingHandlers.numericText = {
    update: function(element, valueAccessor, allBindingsAccessor) {
       var value = ko.utils.unwrapObservable(valueAccessor());
       var positions= ko.utils.unwrapObservable(allBindingsAccessor().positions) || ko.bindingHandlers.numericText.defaultPositions;
       var formattedValue = value.toFixed(positions); 
       var finalFormatted = ko.bindingHandlers.numericText.withCommas(formattedValue);  

        ko.bindingHandlers.text.update(element, function() { return finalFormatted ; });
    },

    defaultPositions: 2,

    withCommas: function(original){
       original+= '';
     x = original.split('.');
    x1 = x[0];
    x2 = x.length > 1 ? '.' + x[1] : '';
    var rgx = /(\d+)(\d{3})/;
    while (rgx.test(x1)) {
        x1 = x1.replace(rgx, '$1' + ',' + '$2');
    }
    return x1 + x2;

    } 
};

var viewModel = {
    myValue: ko.observable(12673.554),
    myPositions: ko.observable(4)
};

ko.applyBindings(viewModel);

/*Just testing the function below, you don't need thsi....*/     



function addCommas(nStr)
{
    nStr += '';
    x = nStr.split('.');
    x1 = x[0];
    x2 = x.length > 1 ? '.' + x[1] : '';
    var rgx = /(\d+)(\d{3})/;
    while (rgx.test(x1)) {
        x1 = x1.replace(rgx, '$1' + ',' + '$2');
    }
    return x1 + x2;
}
var formatted = addCommas('1070781.493')
$('#withComma').val(formatted);

答案 4 :(得分:2)

我使用jQuery Globalize插件接近格式化。 这是我的格式化处理程序版本,textFormattedvalueFormatted分别是文本和值绑定的包装。

用法将是:

<span data-bind="textFormatted: Amount, pattern: 'n'" />

可选地,也可以指定培养物。但我认为这种控制不应该属于HTML,尽管它在开发或调试时间时会有所帮助......

<input data-bind="valueFormatted: Amount, pattern: 'n', culture: 'et'" type="text" />

pattern property / binding的值必须是 Globalize.format( value, format, [locale] )函数的format param期望的任何合适格式。 对于将在可选culture param中使用的locale属性/绑定也是如此。 Globalize reference.

绑定定义:

(function() {

    function getFormatedOrPlainResult(value, allBindingsAccessor) {
        var pattern = allBindingsAccessor.get('pattern');

        if (pattern == null || !/\S*/.test(pattern)) {
            return value;
        }
        var valueToFormat = pattern === 'd' ? new Date(value) : value;
        return Globalize.format(valueToFormat, pattern, allBindingsAccessor.get('culture'));
    };

    ko.bindingHandlers.textFormatted = {
        init: ko.bindingHandlers.text.init,
        update: function(element, valueAccessor, allBindingsAccessor) {
            var result = getFormatedOrPlainResult(ko.unwrap(valueAccessor()), allBindingsAccessor);
            ko.bindingHandlers.text.update(element, function() { return result; });
        }
    };

    ko.bindingHandlers.valueFormatted = {
        init: function(element, valueAccessor, allBindingsAccessor) {
            var result = getFormatedOrPlainResult(ko.unwrap(valueAccessor()), allBindingsAccessor);
            ko.bindingHandlers.value.init(element, function() { return result; }, allBindingsAccessor);
        },
        update: function(element, valueAccessor, allBindingsAccessor) {
            var result = getFormatedOrPlainResult(ko.unwrap(valueAccessor()), allBindingsAccessor);
            ko.bindingHandlers.value.update(element, function() { return result; }, allBindingsAccessor);
        }
    };
}());

答案 5 :(得分:0)

如果只是要显示文本绑定的本地化数字,一种非常简单的方法是使用toLocaleString()

<tr>
  <td data-bind="text: ActualWeight().toLocaleString()"></td>
  <td data-bind="text: TrendWeight().toLocaleString()"></td>
</tr>

有关更多信息,请访问page