Development Tip

KnockoutJS의 숫자 서식 규칙

yourdevel 2020. 12. 3. 20:43
반응형

KnockoutJS의 숫자 서식 규칙


소수 자릿수가 많은 숫자가 많은 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의 다른 사용에 영향을 미칠 수 있기 때문에 약간 무겁게 느껴집니다.


이와 같은 상황을 처리 할 수있는 몇 가지 방법이 있습니다. 바인딩을 통해 주소를 지정하거나 뷰 모델로 푸시 할 수 있습니다.

뷰 모델이 매핑 플러그인에 의해 생성되고 생성 방식을 사용자 지정하지 않으려는 경우 텍스트 바인딩에 대한 래퍼 인 사용자 지정 바인딩을 사용하여 서식을 처리하는 것을 고려할 수 있습니다.

( 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  
};

값을 검사하고 재정의 가능한 기본값을 사용하여 형식을 지정하거나 일부 형식 지정 옵션 ( { type: "numeric", precision: 2 }) 을 전달할 수있는 훨씬 더 일반적인 바인딩 (formattedText)을 만드는 것이 가능합니다 .

시나리오의 경우 첫 번째 옵션이 좋은 선택 일 수 있습니다. 그러나 뷰 모델에 푸시하려면 형식화 된 값과 원시 버전을 모두 반환 할 수있는 특수 관찰 가능 항목을 만들 수 있습니다.

다음과 같을 수 있습니다 ( 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사용자의 요구에 따라. 그렇지 않으면 뒤집어서 기본적으로 원시 값을 반환하고 formatteddependentObservable을 노출 할 수 있습니다. 이와 같은 객체가 JSON으로 변환되면 "하위 관찰 가능 항목"이 손실되므로이 데이터를 서버로 다시 보내는 경우 고려해야 할 사항이 있습니다.

다시 좀 더 일반적으로 만들고 formattedObservable개체 형식 지정 방법에 대한 정보를 가져 오는를 만들 수 있습니다 .

마지막으로 1.3 베타는 extendersAPI를 제공합니다 . 위와 비슷한 작업을 수행 할 수 있습니다. ( 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});

extender는 dependentObservable 자체를 반환하는 대신에 formatteddependentObservable을 추가 할 수도 target있습니다.


녹아웃은 이제 익스텐더를 지원하므로 사용자 지정 바인딩 대신 익스텐더 를 사용합니다. 바인딩은 다음과 같습니다.

<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이 경우 익스텐더 를 작성해야합니다 . 녹아웃 문서에 예제가 제공됩니다.


통화 및 퍼센트 형식을 지정하기 위해 http://adamwdraper.github.com/Numeral-js/ 에서 찾을 수있는 numeric.min.js와 함께 사용할 사용자 지정 바인딩 numericformat.js를 만들었습니다.

numericformat.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>

위에서 받아 들여진 답변을 기반으로합니다. 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);

jQuery Globalize 플러그인을 사용하여 서식 지정에 접근했습니다. 여기에 서식 핸들러의 내 버전입니다, textFormattedvalueFormatted텍스트와 값 바인딩에 대한 래퍼는 각각이다.

사용법은 다음과 같습니다.

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

선택적으로 문화도 지정할 수 있습니다. 하지만 이런 종류의 컨트롤은 HTML에 속해서는 안된다고 생각 합니다만, 개발이나 디버깅시 도움이 될 수 있습니다.

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

Values for pattern property/binding must be any of suitable formats that Globalize.format( value, format, [locale] ) function's format param expects. Same goes for culture property/binding that will be used in optional locale param. Globalize reference.

Binding definitions:

(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);
        }
    };
}());

If it's just about displaying a localized number of a text binding, a very easy way is to use toLocaleString()

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

For more information visit page.

참고URL : https://stackoverflow.com/questions/7704268/formatting-rules-for-numbers-in-knockoutjs

반응형