thousand separator on an input - on key up

2,463 views
Skip to first unread message

Michiel Kikkert

unread,
May 14, 2013, 6:23:21 AM5/14/13
to ang...@googlegroups.com
Hi,

Just starting to learn AngularJS and so far I love it!

I ran into my first real challenge whereby I have a requirement to allows users to input values into an input field - and while they type, the input value should be modified with thousand separators (in my case a dot for european currency format).

So basically, the input should have the separator, but the corresponding model should NOT have the dot (but only the clean value).

I have been thinking about multiple approaches but I keep running into scoping issues and the fact that the view representation is different from the model. So far, I came up with a directive that kind of does what I need, but still has some issues.

The view looks like this in it simplest form:

<input thousand-separator="\." type="text" data-ng-model="testvalue"/>

And the Directive:

.directive('thousandSeparator', [ '$timeout', function($timeout) {
        return {
            require: 'ngModel',
            link: function(scope, element, attrs, controller){
                var sep = attrs.thousandSeparator || ".";
                var model = attrs.ngModel;

                var doReplace = function(){
                    var curValue = element.val();
                    var replace = new RegExp(sep, 'g');
                    var cleanValue = curValue.replace(replace, "");
                   
                    // Create dotted value from clean
                    var x1 = cleanValue + '';
                    var rgx = /(\d+)(\d{3})/;
                    while (rgx.test(x1)) {
                        x1 = x1.replace(rgx, '$1' + '.' + '$2');
                    }

                    element.val(x1);

                    scope.$apply(function () {
                        controller.$setViewValue(cleanValue);
                    });
                }


                element.on('keyup', function(){
                    doReplace();
                });

                element.on('blur', function(){
                    doReplace();
                  
                });

                // trigger for existing model values
                $timeout(doReplace,1);

            }
        }
    }])


So this kinda works - check the Plunker here: http://plnkr.co/edit/jY3itHHtHWTJmbDsoInp?p=preview
It shows the dotted value in the input (while you type) and the testvalue model updates (slightly delayed).

I have my doubts of this is the correct way of doing it. It seems slightly hacky to me so I'm looking for some feedback or different approaches on how to do this.

Also, I have problem if I put this directive in an NgRepeat loop - the model no longer updates then?

See plunker for that issue here: http://plnkr.co/edit/0berlPHhnFymCdsAGrz7?p=preview

Any input appreciated!







Michiel Kikkert

unread,
May 14, 2013, 6:31:24 AM5/14/13
to ang...@googlegroups.com
Damn - code in the posts doesn't seem to be allowed... (????) - reposting with just the plunkers.. Moderator - feel free to delete this one..

Eduard Gamonal

unread,
May 14, 2013, 7:03:38 AM5/14/13
to ang...@googlegroups.com
hi Michiel,
an implementation with filters looks much simpler, doesn't it?
The explanation here might help you http://docs.angularjs.org/tutorial/step_09

about your ngrepeat problem, have a look here http://www.youtube.com/watch?v=ZhfUv0spHCY&t=29m19s
ngrepeat creates a new scope for each item.

--
You received this message because you are subscribed to the Google Groups "AngularJS" group.
To unsubscribe from this group and stop receiving emails from it, send an email to angular+u...@googlegroups.com.
To post to this group, send email to ang...@googlegroups.com.
Visit this group at http://groups.google.com/group/angular?hl=en-US.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Michiel Kikkert

unread,
May 14, 2013, 7:12:13 AM5/14/13
to ang...@googlegroups.com
Hi Eduard,

I couldn't think of a way to make this possible with a filter - don't forget, I don't simply want to show the value somewhere with {{ testvalue }} (that's indeed simply done with a filter) - the actual input value needs to be updated on the fly...

I understand the limited scoping of an ngRepeat - but I do not know how to resolve it in my scenario :-)

Michiel Kikkert

unread,
May 14, 2013, 7:16:23 AM5/14/13
to ang...@googlegroups.com
Maybe I'm missing something - that's very possible :-)

Could you give an example of how to do this specific scenario with a filter?


On Tuesday, May 14, 2013 1:03:38 PM UTC+2, Eduard Gamonal wrote:

Michiel Kikkert

unread,
May 14, 2013, 8:25:49 AM5/14/13
to ang...@googlegroups.com
Never mind about the second (scoping) question. I've got this working now by changing the model to an array of objects instead of primitives: http://plnkr.co/edit/0berlPHhnFymCdsAGrz7?p=preview

Michiel Kikkert

unread,
May 14, 2013, 9:35:17 AM5/14/13
to ang...@googlegroups.com
This seems to be the best solution (by
Ryan Randall):
 
2:09 PM (1 hour ago)
You can use a combination of $parsers and $formatters. Here's an example: http://plnkr.co/edit/0Ger5fFzwPJQbJzwoflV?p=preview


Take a look at http://docs.angularjs.org/guide/i18n for international currency formats.

Matteo Suppo

unread,
Mar 25, 2014, 7:04:17 AM3/25/14
to ang...@googlegroups.com
If you start writing a negative number with the minus sign it would not work. It would not work even if you wanted to write decimal numbers

I fixed it: http://plnkr.co/edit/WiFRg43Yol36V2KecKWK?p=preview
Reply all
Reply to author
Forward
0 new messages