Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there masked input plugin for knockout.js using extenders?

I've seen this post - it shows one possible solution. But I would like to have a more elegant way of doing masked input.

It should also play nicely with knockout validation plugin (or maybe extending it).

Anyone know how is there similar project out there?

like image 703
kyrisu Avatar asked Nov 28 '12 11:11

kyrisu


4 Answers

If you wanted to use the excellent Masked Input Plugin in Knockout, it's pretty easy to write a basic custom binding rather than an extender.

ko.bindingHandlers.masked = {
    init: function(element, valueAccessor, allBindingsAccessor) {
        var mask = allBindingsAccessor().mask || {};
        $(element).mask(mask);
        ko.utils.registerEventHandler(element, 'focusout', function() {
            var observable = valueAccessor();
            observable($(element).val());
        });
    }, 
    update: function (element, valueAccessor) {
        var value = ko.utils.unwrapObservable(valueAccessor());
        $(element).val(value);
    }
};

And then in your HTML:

<input type="text" data-bind="masked: dateValue, mask: '99/99/9999'" />
<input type="text" data-bind="masked: ssnValue, mask: '999-99-9999'" />

And so on with various masks. This way, you can just put the mask right in your databinding, and it allows a ton of flexibility.

like image 96
Jason Clark Avatar answered Oct 08 '22 00:10

Jason Clark


Well done, riceboyler. I took your code and extended it a little in order to use the "placeholder" property of the Masked Input Plugin:

    ko.bindingHandlers.masked = {
        init: function (element, valueAccessor, allBindingsAccessor) {
            var mask = allBindingsAccessor().mask || {};
            var placeholder = allBindingsAccessor().placeholder;
            if (placeholder) {
                $(element).mask(mask, { placeholder: placeholder });
            } else {
                $(element).mask(mask);
            }
            ko.utils.registerEventHandler(element, "blur", function () {
                var observable = valueAccessor();
                observable($(element).val());
            });
        },
        update: function (element, valueAccessor) {
            var value = ko.utils.unwrapObservable(valueAccessor());
            $(element).val(value);
        }
    };

HTML with placeholder:

    <input id="DOB" type="text" size="12" maxlength="8" data-bind="masked: BirthDate, mask: '99/99/9999', placeholder: 'mm/dd/yyyy', valueUpdate: 'input'"/>

HTML without placeholder:

    <input id="DOB" type="text" size="12" maxlength="8" data-bind="masked: BirthDate, mask: '99/99/9999', valueUpdate: 'input'"/>

The KO binding works either way.

like image 30
hoyt1969 Avatar answered Oct 08 '22 00:10

hoyt1969


Just take the code from the answer in that link and put it in a extender (Written on free hand, can have errors)

ko.extenders.masked = function(observable, options) {
    return ko.computed({
        read: function() {
            return '$' + this.observable().toFixed(2);
        },
        write: function(value) {
            // Strip out unwanted characters, parse as float, then write the raw data back to the underlying observable
            value = parseFloat(value.replace( /[^\.\d]/g , ""));
            observable(isNaN(value) ? 0 : value); // Write to underlying storage
        }
    });
};

edit: You probably want to supply the mask as a options instead of having it hardcoded to USD etc

update: If you want to use the mask plugin from riceboyler's answer but with extenders you can do

ko.extenders.mask = function(observable, mask) {
    observable.mask = mask;
    return observable;
}


var orgValueInit = ko.bindingHandlers.value.init;
ko.bindingHandlers.value.init = function(element, valueAccessor) {
    var mask = valueAccessor().mask;
    if(mask) {
        $(element).mask(mask);
    }

    orgValueInit.apply(this, arguments);
}

http://jsfiddle.net/rTK6G/

like image 30
Anders Avatar answered Oct 08 '22 00:10

Anders


I tried to use the first answer but it did not work with ko.validation plug in. My validation errors were not being displayed.

I wanted to have little bit more intuitive ko binder. Here is my solution. I am using jquery.inputmask plug in. I also wipe out the property on my viewmodel if not value entered.

    ko.bindingHandlers.mask = {
        init: function (element, valueAccessor, allBindingsAccessor, viewModel,     bindingContext) {
            var mask = valueAccessor() || {};
            $(element).inputmask({ "mask": mask, 'autoUnmask': false });
            ko.utils.registerEventHandler(element, 'focusout', function () {
                var value = $(element).inputmask('unmaskedvalue');            
                if (!value) {
                    viewModel[$(element).attr("id")]("");                
                }
            });
        }
    };

Here is the usage:

<input type="text" data-bind="value: FEIN, mask: '99-9999999'" id="FEIN" >
like image 25
benk Avatar answered Oct 08 '22 01:10

benk