0

Hi Guys I want to write a angular directive which encodes the input text to html. So that critical characters are converted. For example ö -> &ouml
I have found this nice library, which I want to use.

My problem is I want to have this convertation only in my model. The user shouldn't see anything from this.

For now I have tried this way. But this doesn't do what I want. I'm new to angular and don't get comfortable with directives. Maybe you can help me.

angular.module('schwimmfestivalAngApp')
    .directive('encodedInput', function () {
        return {
            restrict: 'A',
            require: 'ngModel',
            link: function (scope, element, ctrl, he) {

                element.bind('onblur',
                    function () {
                        ctrl.$modelValue = he.encode(ctrl.$viewValue, {
                            'useNamedReferences': true
                        });
                    }
                )
                ;

            }
        };
    });
1
  • 1
    The link function receives it parameters in a set order. namely: link(scope, iElement, iAttrs, controller, transcludeFn). You seem to have this a bit mixed up. Commented Mar 15, 2016 at 12:31

2 Answers 2

1

This is definitely not a beginner's task as you need to have a bit more experience with Angular to make it work as expected.

Manipulating data between view and model in an Angular directive has two parts. One that does conversion from model to view and the other that does conversion from view to model. Basically you should manipulate data in both directions, so your view displays something while your model holds a manipulated value that satisfies your requirements.

Model ⇒ View

You should implement $render function to aid this part:

ngModelController.$render = function() {
    ...
}

View ⇒ Model

This part may implement several things. The most important thing in your scenario is probably calling $setViewValue function

element.on("blur", function(evt) {
    ngModelController.$setViewValue(...);
});

Naming may be a bit misleading here as we want data model value to change and not view model value, but read this excerpt directly from docs:

When $setViewValue is called, the new value will be staged for committing through the $parsers and $validators pipelines. If there are no special ngModelOptions specified then the staged value sent directly for processing, finally to be applied to $modelValue and then the expression specified in the ng-model attribute. Lastly, all the registered change listeners, in the $viewChangeListeners list, are called.

But there're also directive parsers that can manipulate your view value before it gets committed to the model.

ngModelController.$parsers.push(customParser);

function customParser(value) {
    return /* some value */;
}

Documentation details

Make sure you thoroughly read the ngModelController documentation.

Important note

Make sure you implement several other points mentioned in this documentation by only adding console logs so you can get a grasp of directive execution cycle.

Sign up to request clarification or add additional context in comments.

3 Comments

First: Thank you for this good explanation. This seems to be a lot of hard work. Is it simpler to convert the input and save it to an other variable?
Depends on use. If this directive is a one off, than maybe yes, but I'd argue that this is not too complicated. It's just convention one needs to follow. Many things in Angular may be a bit more convoluted, but they're there for a reason. If you have several directives that would require similar functionality but different manipulation, you could however create a common directive but add additional parameters that would point to your specific manipulator functions.
I create this fiddle jsfiddle.net/8y10Lg9t but I don't get it to work. There is a little error that always added &amp to my string. Maybe someone get the fiddle to work with angular. Than I could try to show up the error.
0

Thanks to Robert for his hints. I think I have figured it out now.

For me it works but not seems to be the perfect way.

This is for now how my directive looks for now.

.directive('encodedInput', function ($window) {
    return {
      restrict: 'A',
      require: '?ngModel',
      link: function (scope, element, attrs, ngModel) {
        if (!ngModel) return; // do nothing if no ng-model

        // Specify how UI should be updated
        ngModel.$render = function () {
          element.html($window.he.decode(ngModel.$modelValue || ''));
        };

        var inputString = '';

        // Listen for change events to enable binding
        element.on('blur keyup change', function () {

          //Check wether the string has changed. So the & will not be extra encoded.
          if (inputString != ngModel.$viewValue) {//Combined without logging
            console.log(length);
            length = inputString.length;
            ngModel.$setViewValue($window.he.encode(ngModel.$viewValue, {
              'useNamedReferences': true
            }));
          }
          inputString = ngModel.$viewValue;
        });
        function read(string) {

        }
      }
    };
  }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.