📜 ⬆️ ⬇️

Masking numeric values ​​using autoNumeric and Knockout

In general, I had the task to rewrite one of the controls built on the repeater and make it easier, more responsive for the client. At the same time I decided to use knockout. Inside, DevExpress's text fields were used to display digital data, they are very convenient and served properly, but then the question arose, what about when replacing with regular text fields, I can add a mask.



Start


')
In order to solve this problem, I began to look for what are the normal jquery plugins or libraries that will allow you to quickly and easily solve the problem. As a result, I found two libraries:



Analysis



Looking at the capabilities of the libraries, I could say for sure that I would use autoNumeric , since it has the ability not to show the input mask, but to process the input value on the fly. Its behavior is similar to the behavior of the text box DevExpress. The jquery.maskedinput plugin, unfortunately, did not find such an opportunity. There is only the possibility of entering data using a strict mask, which then appears in the text field, informing the user about the upcoming input format. For my case, this treatment is not suitable.

Application



Well, with the choice of the data masking library in the text field, I decided, but how can I tie a mask for the fields. First there was the idea to set a specific class for all required fields using a single input format, and then use the jquery to feed the autoNumeric library. But it seemed to me that this decision would not be very convenient.
Then I thought, why not use the power of knockout! Since knockout allows you to implement custom handlers for data binding, I decided to create just such a handler and specify it in the data-bind="" attribute.

Little about autoNumeric


I give the value of some useful methods used by me in solving the problem:



I give the value of the options passed to the autoNumeric() method as a parameter:



An example of the transfer, used by me options, to configure autoNumeric:

 $('.autonum').autoNumeric({ aSep: ',', aDec: '.', mDec: 0 }); 


* This means that autoNumeric will use ',' for the separator of hundreds of the whole part and '.' as a fraction separator. Also, the number of digits after the fractional separator will be 0 (i.e. whole numbers will be displayed).

Implementation using knockout


Implementing a custom data binding handler for autoNumeric


  ko.bindingHandlers.numberMaskedValue = { init: function(element, valueAccessor, allBindingsAccessor) { //  ,    , //     var options = allBindingsAccessor().autoNumericOptions || { aSep: ',', aDec: '.', mDec: 0 }; // html       $(element).autoNumeric(options); //   'focusout' , //     observable  ko.utils.registerEventHandler(element, 'focusout', function() { var observable = valueAccessor(); //        value = $(element).autoNumericGet(); observable(isNaN(value) ? 0 : value); }); }, update: function(element, valueAccessor) { var value = ko.utils.unwrapObservable(valueAccessor()); //   ,   ,  $(element).autoNumericSet(value); } }; 


The above implementation allows using this handler in this way:

 <input type="text" data-bind="numberMaskedValue: countOfFriends"/> 


or with options:

 <input type="text" data-bind="numberMaskedValue: countOfFriends, autoNumericOptions:{aSep: ',', aDec: '.', mDec: 3}"/> 


In this example handler, the value will be updated at the event 'focusout' . For the user, the entered value will look beautiful, and in a real observable property, it will remain suitable for arithmetic processing. Thus, I can immediately solve two problems: binding the desired (transfer) autoNumeric control, and passing (updating) the value in the observable property.

Full sample code
Html


 <div data-bind="foreach: humans"> <div class="block-of-data"> <div> <label class="label label-info">id</label> <span data-bind="text: id"></span> </div> <div> <label class="label label-info">Name</label> <span data-bind="text: name"></span> </div> <div> <label class="label label-info">Count of friends</label> <input type="text" data-bind="numberMaskedValue: countOfFriends"/> </div> <div> <label class="label label-interest">Real value "Count of friends"</label> <span data-bind="text: countOfFriends"></span> </div> </div> <div> 


Javascript


 $(function() { ko.bindingHandlers.numberMaskedValue = { init: function(element, valueAccessor, allBindingsAccessor) { var options = allBindingsAccessor().autoNumericOptions || { aSep: ',', aDec: '.', mDec: 0 }; $(element).autoNumeric(options); ko.utils.registerEventHandler(element, 'focusout', function() { var observable = valueAccessor(); value = $(element).autoNumericGet(); observable(isNaN(value) ? 0 : value); }); }, update: function(element, valueAccessor) { var value = ko.utils.unwrapObservable(valueAccessor()); $(element).autoNumericSet(value); } }; function Human(idv, namev, countOfFriendsv) { var id = ko.observable(idv), name = ko.observable(namev), countOfFriends = ko.observable(countOfFriendsv); return { id: id, name: name, countOfFriends: countOfFriends } } function HumansModel() { humans = ko.observableArray([new Human(1,'Alex', 1234), new Human(2,'Bob',12457)]); } ko.applyBindings(new HumansModel()) }); 


Css


 .block-of-data{ border: solid 1px black; margin:10px; padding: 5px; background-color:#ffffaa; -webkit-border-radius: 10px; -moz-border-radius: 10px; border-radius: 10px; } .label { padding: 1px 4px 2px; -webkit-border-radius: 3px; -moz-border-radius: 3px; border-radius: 3px; } .label { font-size: 10.998px; font-weight: bold; line-height: 14px; color: white; text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); white-space: nowrap; vertical-align: baseline; background-color: #999; } .label-info { background-color: #3A87AD; } .label-interest { background-color: #ff7722; } 




Links




Thanks for attention!

Source: https://habr.com/ru/post/149010/


All Articles