Jerome2606
Jerome2606

Reputation: 955

directive $formatters affect ngModel when writing

I have a problem to use $formatters.

My goal is to hide phone number, just leave the last 4 chars visible. It's ok if you don't write anything in the input. If you write something, the model is affected by the mask and I register the hidden phone in DB ...

Here's the directive I use:

.directive('tsHideField', function () {
return {
    require: 'ngModel',
    restrict: 'A',
    link: function (scope, element, attributes, controller) {

        var maskValue = function (value) {
            if (!value) {
                return "";
            }
            if (value.length <= 4) {
                return value;
            }
            var valueHide = "";
            if (value.indexOf('@') === -1) {
                //leave last 4 chars
                valueHide = value.toString().substring(0, value.length - 4).replace(/[\S]/g, "\u2022");
                return valueHide + value.toString().substring(value.length - 4);
            } else {
                //Adresse email, on laisse après le @ et on cache tout sauf les 4 dernières lettre avant
                //'[email protected]'.substring(0,'[email protected]'.indexOf('@') - 4).replace(/[\S]/g, "\u2022") + '[email protected]'.substring('[email protected]'.indexOf('@') - 4)
                valueHide = value.toString().substring(0, value.indexOf('@') - 4).replace(/[\S]/g, "\u2022");
                return valueHide + value.toString().substring(value.indexOf('@') - 4);
            }

            // replace all characters with the mask character
            //return (value || "").replace(/[\S]/g, "\u2022");
        }

        /** SI ON VEUT EGALEMENT CACHER A L ECRIT:
         * 
         * var createMaskedInputElement = function() {
            if (! maskedInputElement || ! maskedInputElement.length) {
                maskedInputElement = element.clone(true);
                maskedInputElement.attr("type", "password"); // ensure the value is masked
                maskedInputElement.removeAttr("name"); // ensure the password save prompt won't show
                maskedInputElement.removeAttr("core.application.main.directive.mask"); // ensure an infinite loop of clones isn't created
                maskedInputElement.bind("blur", function() {
                    element.removeClass("ng-hide");
                    maskedInputElement.remove();
                    maskedInputElement = null;
                });
                $compile(maskedInputElement)(scope);
                element.after(maskedInputElement);
            }
        };

        element.bind("focus", function() {
            createMaskedInputElement();
            element.addClass("ng-hide");
            maskedInputElement[0].focus();
        });
         */

        controller.$formatters.push(function (value) {
            return maskValue(value);
        });

    }
};
});

And for your facility, here's a fiddle with a little implementation: http://jsfiddle.net/nqp4qtLk/2/

How to prevent model to be affected by the mask ??

EDIT: I adapt the answer of Gr3g to match to my requirements

see the updated fiddle: Updated fiddle

Upvotes: 5

Views: 136

Answers (3)

kaps
kaps

Reputation: 478

You can use $parsers.push to control value to be saved in the model.

    var unmask = function(value) {
        var original = scope.vm.phone.toString();                   
        var last4 = value.substring(value.length-4);
        var newstr = original.substring(0, original.length-4);
        return (newstr+last4);   
        // you can have whatever logic you want, to manipulate the original value
    }

    controller.$parsers.push(function (value) { 
        return unmask(value);
        // or do what ever you want.
    });

Updated fiddle- http://jsfiddle.net/anh9y8d9/3/

Upvotes: 0

gr3g
gr3g

Reputation: 2914

Please see my EDITED fiddles :

If you don't allow *'s to be deleted :
Fiddle

If you allow *'s to be deleted :
Punker

Note :
If you allow *'s to be deleted, you will see in the plunker I do not allow following :
- Deleting star(s) when number(s) are visible.
- Adding a number between 2 stars or at the first position.

Code has grown up so I can only show you partial code here.
Obviously, you needed the $parsers pipeline :

controller.$parsers.push(function(val){
 //Modify your value
 return modifiedValue || val;
});

Notice i added 2 functions in each pipeline so I can access a String in the function where I need to modify the value. I don't have to care (too much) about casts.

controller.$parsers.unshift(function(val){
  return String(val);
});

You can probably make it faster, but be careful when refactoring to think about all possibilities to handle. Especially when *'s can be deleted.

Upvotes: 2

Walfrat
Walfrat

Reputation: 5353

I don't think you can, imagine i go between 2 points and delete one, how will you do ?

You should use 2 differents components : one to type each character, the other showing the phone number with only 4 last displayed.

The hardest possible way : handle all key event on the input yourself so you could even resolve what i said in the beginning of my post.

Upvotes: 0

Related Questions