1

Objective: Ability to hide/mask a substring of a text input field, without affecting the ng-model variable

Example:

<input type="text" placeholder="enter URL" ng-model="input.url" mask="dilbert">

If the user enters admin:dilbert@mylocation.host.com then the display shows admin:*******@mylocation.host.com while $scope.input.url will contain admin:dilbert@mylocation.host.com

Is this possible? I have a situation where I just need to hide the password inside URLs when displaying forms, should the user enter it. The workaround is to keep a display variable and a cloned actual variable but that is not really an elegant solution.

Further motivation explained (to address WilliamB's comment below)

This requirement is for a mobile app which requires a URL to be configured. That URL may include basic auth credentials if the user has configured the backend server to use basic auth (Every user of this mobile app uses their own server)

Here is a sample screen shot: enter image description here

The ask

a) When the URL field is displayed, but not being edited, the password is masked without affecting the model variable

b) To keep this simple, when the URL fields are being edited, the password is displayed as regular text (in focus)

c) the mask='string' ask was a simplification. In reality, this usecase would likely be a mask directive and if attached to an input text field, would mask the password text when input is of format url://user:password@domain/path

I realize this is only a basic masking - but its a mobile app, and very few people will start dissecting DOMs to look at what is masked

user1361529
  • 2,667
  • 29
  • 61

2 Answers2

1

ngModel's controller gives the ability to set the view value for the DOM. Like so:

.directive('mask', function () {
  return {
    require: 'ngModel',
    link: function (scope, elem, attrs, ngModelCtrl) {
      scope.$watch(attrs.ngModel, function (newVal, oldVal) {
        var mask = attrs.mask.replace(/./g, function () { return '*' });
        ngModelCtrl.$viewValue = newVal.replace(attrs.mask, mask);
        ngModelCtrl.$render();
      });
    }
  }
});

here is an example fiddle: https://jsfiddle.net/7kLb38ys/1/

William B
  • 1,411
  • 8
  • 10
  • Lovely. I will dive in more tomorrow morning - one issue I see is if I try and edit the text input after it converts dilbert to *******, (say delete t) the model value becomes all stars instead of dilber – user1361529 Nov 16 '16 at 02:48
  • Yup verified - every time you edit, the "*"s overwrite the ng-model variable, which I need to avoid – user1361529 Nov 16 '16 at 16:08
  • I think the behavior you are describing isn't fully fleshed out. what if you start backspacing, or what if you type in the middle of the "*" characters, then what should happen to the model and the masking? Why are you masking these characters but showing the text in the HTML via `mask="dilbert"`? If you describe your actual use case there is probably a more sensible option such as masking the entire field via `type="password"` – William B Nov 17 '16 at 01:06
  • I've added clarifications to my original post. I do have a question though - why is it that on editing _anything_ in your fiddle, the viewValue *s get copied to the model value? I thought the entire objective of viewValue was to not affect the ng-model? – user1361529 Nov 17 '16 at 16:17
0

The final solution that works exactly as I want: (doesn't include a generic mask, but can be easily modified if needed - my real need was to hide the user:password field of a URI)

//credit: http://stackoverflow.com/a/23931217/1361529
.directive('hidepassword', function () {

  var modelSet = function (str)
  {

        return str;
  };

  var viewSet = function (str)
  {
        //URI.js: https://github.com/garycourt/uri-js
        if (!str) return str;
        var c = URI.parse(str);
        if (c.userinfo) c.userinfo="***:***";
        var vc = URI.serialize({scheme : c.scheme, 
                                userinfo: c.userinfo,
                                host: c.host,
                                port: c.port,
                                path: c.path,
                                query: c.query,
                                fragment: c.fragment
                                });
        console.log ("CONVERTED IS "+vc);


        return vc;
  };

  return {

    restrict: 'A',
      require: 'ngModel',
      link: function (scope, element, attr, ngModel) {
        ngModel.$parsers.push(modelSet);
        ngModel.$formatters.push(viewSet);

        element.bind('blur', function() {
          element.val(viewSet(ngModel.$modelValue));
        });
        element.bind('focus', function () {
          element.val(ngModel.$modelValue);
        });

      }
  };
})
user1361529
  • 2,667
  • 29
  • 61