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

前端 未结 5 1999
孤独总比滥情好
孤独总比滥情好 2021-02-02 14:21

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 valida

相关标签:
5条回答
  • 2021-02-02 14:47

    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/

    0 讨论(0)
  • 2021-02-02 14:53

    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" >
    
    0 讨论(0)
  • 2021-02-02 15:00

    You can use this homemade solution, work perfectly for me:

    My Binding knockout call masked inspired from the net, i added some managed language and update from different event. Also I use this js library for using basically : https://plugins.jquery.com/maskedinput/

    You can see in my binding the term "allBindingsAccessor().mask" this is from the library maskedinput

     ko.bindingHandlers.masked = {
        init: function (element, valueAccessor, allBindingsAccessor) {
            var mask = allBindingsAccessor().mask || {},
            getCaretPosition,
            setCaretPosition;
    
            // Permet d'obtenir la position du curseur
            getCaretPosition = function getCaretPosition(element) {
                // Initialise la position
                var caretPos = 0, sel;
    
                // IE 
                if (document.selection) {
                    // Donne le focus à l'élément
                    element.focus();
                    // Afin d'obtenir la position du curseur
                    sel = document.selection.createRange();
                    // On place le curseur à 0
                    sel.moveStart('character', -element.value.length);
                    caretPos = sel.text.length;
                }
                    // Firefox 
                else if (element.selectionStart || element.selectionStart === '0') {
                    caretPos = element.selectionStart;
                }
                return (caretPos);
            };
    
            // Permet de définir la position du curseur en fonction d'une position donnée
            setCaretPosition = function setCaretPosition(element, pos) {
                var range;
                if (element.setSelectionRange) {
                    element.focus();
                    element.setSelectionRange(pos, pos);
                }
                else if (element.createTextRange) {
                    range = element.createTextRange();
                    range.collapse(true);
                    range.moveEnd('character', pos);
                    range.moveStart('character', pos);
                    range.select();
                }
            };
    
            // Définition du masque inséré dans le champ
            if (configSvc.culture === "fr-FR") {
                // Cas francais
                $(element).mask("99/99/9999", { placeholder: "JJ/MM/AAAA" });
            }
            else {
                // Cas anglophone
                $(element).mask("99/99/9999", { placeholder: "MM/DD/YYYY" });
            }
    
            // On capte l'événement d'appuie sur une touche 
            ko.utils.registerEventHandler(element, 'keypress', function () {
                var observable = valueAccessor(),
                    position;
                // Afin de résoudre le pb de déplacement du curseur a la fin du mask lors de la mise à jour de l'observable knockout
                if ($(element).val().length === 10) {
                    // On récupère la dernière position
                    position = getCaretPosition(this);
                    // On met à jour la valeur de l'obersable (en cas de sauvegarde) 
                    observable($(element).val());
                    // On force la position du curseur apres mise à jour de l'observable à la derniere position récupéré
                    setCaretPosition(this, position);
                }
            });
    
            // On capte l'événement de perte de focus pour mettre l'obersable à jour
            ko.utils.registerEventHandler(element, 'blur', function () {
                var observable = valueAccessor();
                observable($(element).val());
            });
    
            // On capte l'événement change pour mettre l'obersable à jour
            ko.utils.registerEventHandler(element, 'change', function () {
                var observable = valueAccessor();
                observable($(element).val());
            });
        },
        update: function (element, valueAccessor) {
            var value = ko.utils.unwrapObservable(valueAccessor());
            $(element).val(value);
        }
    
    };
    

    in my html page, i use this observable "masked" :

    <input type="text" id="head-birthDate" class="form-control" data-bind="masked: birthDate" />
    

    Finally in my js :

    birthDate is just an observable

    this.birthDate = ko.observable();
    
    0 讨论(0)
  • 2021-02-02 15:10

    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.

    0 讨论(0)
  • 2021-02-02 15:10

    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.

    0 讨论(0)
提交回复
热议问题