Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
509 views
in Technique[技术] by (71.8m points)

jquery - KnockoutJS intercept to one decimal place

I know variations of this have been asked, but my requirement is that instead of formatting/rounding the value that's entered, I need to not even allow the user to enter more than one number after the decimal point. I have something that works with a decimalFormatter binding handler, but it's clunky - i.e., it allows you to enter a value like '20.' and you can't erase all the values due to the way I have the regular expression written. I realize I could modify that to accept optional digits for the whole entry, but what I really want is for it to revert to 0.0 if the user erases the value. And, allow for them to enter '20.' then tab out (onblur) and have it reformat the value to 20.0 so it looks more complete. Currently, if the user enters '20.' then saves the form, it does store a whole value of 20, and when you reopen/retrieve the value from the database, it shows 20.0 so it looks fine when reloading.

I thought about adding an onblur event but we don't want to do that in overriding what has been databound by knockout. We want to keep everything bound by the ko view model, so that's not an option. I've also seen some suggest a computed observable (for example this SO post) but my binding already does that. On second thought, would the knockout event binding be the way to go here???

html:

<input style="width:38px" data-bind="decimalFormatter: percentage"/>

javascript:

ko.bindingHandlers.decimalFormatter = {
    init: function (element, valueAccessor) {
    var initialValue;

    //$(element).on('keydown', function (event) {
    $(element).keydown(function (event) {
        initialValue = $(element).val();

        // Allow: backspace, delete, tab, escape, and enter
        if (event.keyCode == 46 || event.keyCode == 8 || event.keyCode == 9 || event.keyCode == 27 || event.keyCode == 13 ||
        // Allow: Ctrl combinations
        (event.ctrlKey === true) ||
        // Allow decimal/period
        (event.keyCode === 110) || (event.keyCode === 190) ||
        // Allow: home, end, left, right
        (event.keyCode >= 35 && event.keyCode <= 39)) {
            // let it happen, don't do anything
            return;
        }
        else {
            // Ensure that it is a number and stop the keypress
            if (event.shiftKey || (event.keyCode < 48 || event.keyCode > 57) && (event.keyCode < 96 || event.keyCode > 105)) {
                event.preventDefault();
            }
        }
    });

    $(element).keyup(function (event) {
        if (!$(element).val().match(/^d+.?d?$/)) {
            event.preventDefault();
            $(element).val(initialValue);
        }
        else
            return;
    });        

    var observable = valueAccessor();

    var interceptor = ko.computed({
        read: function () { return formatWithComma(observable(), 1); },
        write: function (newValue) {
            observable(reverseFormat(newValue, 1));
        }
    });

    if (element.tagName == 'INPUT')
        ko.applyBindingsToNode(element, { value: interceptor });
    else
        ko.applyBindingsToNode(element, { text: interceptor });
    },
    update: function (element, valueAccessor) {
    }
}

// Formatting Functions
function formatWithComma(x, precision, seperator) {
    var options = {
        precision: precision || 2,
        seperator: seperator || '.'
    }
    var formatted = parseFloat(x, 10).toFixed(options.precision);
    var regex = new RegExp('^(\d+)[^\d](\d{' + options.precision + '})$');
    formatted = formatted.replace(regex, '$1' + options.seperator + '$2');
    return formatted;
}

function reverseFormat(x, precision, seperator) {
    var options = {
        precision: precision || 2,
        seperator: seperator || '.'
    }

    var regex = new RegExp('^(\d+)[^\d](\d+)$');
    var formatted = x.replace(regex, '$1.$2');
    return parseFloat(formatted);
}

var viewModel = function () {
    var self = this;
    self.percentage = ko.observable(20.0);
};

var vm = new viewModel();
ko.applyBindings(vm);

JSFiddle

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Well i used AUTONUMERIC plugin for number formatting which was reliable and awesome .

I just made a sample fiddle to your requirement check it here

View Model:

var vm = function(){   
this.Amount=ko.observable(""); 
this.OnloadAmount=ko.observable(143); //onLoad Test
ko.bindingHandlers.autoNumeric = {
       init: function (el, valueAccessor, bindingsAccessor, viewModel) {
            var $el = $(el),
              bindings = bindingsAccessor(),
              settings = bindings.settings,
              value = valueAccessor();

            $el.autoNumeric(settings);
            $el.autoNumeric('set', parseFloat(ko.utils.unwrapObservable(value()), 10));
            $el.change(function () {
                value(parseFloat($el.autoNumeric('get'), 10));
            });
        },
        update: function (el, valueAccessor, bindingsAccessor, viewModel) {
            var $el = $(el),
              newValue = ko.utils.unwrapObservable(valueAccessor()),
              elementValue = $el.autoNumeric('get'),
              valueHasChanged = (newValue != elementValue);

            if ((newValue === 0) && (elementValue !== 0) && (elementValue !== "0")) {
                valueHasChanged = true;
            }

            if (valueHasChanged) {
                $el.autoNumeric('set', newValue);
            }
        }
    };
}

  ko.applyBindings(new vm());

View :

<input type="text"  data-bind="autoNumeric:$data.Amount, settings:{mDec:1,aSep: ''} " />

Here mDec:1 restricts number to decimal palce of one and asep:'' means it will not sperate number with commas etc

PS: we can restrict entering invalid characters and do lots of other stuff with ease .

For complete Reference check here


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

1.4m articles

1.4m replys

5 comments

57.0k users

...