如何在自定义指令中使用ngModel指令的格式化程序/解析器?

时间:2015-08-21 22:53:34

标签: javascript angularjs

我想在我的指令中使用ng-model格式化程序/解析器。问题是格式化程序没有按预期工作它正确返回结果但它没有应用于输入框。 (请参阅演示中的控制台日志)。

如果我直接在输入标签上运行指令而没有我的指令模板,它按预期工作。我看不出有什么问题。 这可能是一个范围问题,但我不确定。我该如何解决这个问题?

该指令如何工作

该指令在模型中存储HTML实体(例如©),并在文本输入字段中显示为版权符号(©)。稍后,我将使用按钮添加符号到文本字段。对于我来说,学习Angular并不是一个真正的应用程序。

以下是我的代码演示或此jsfiddle

angular.module('demoApp', ['ngSanitize'])
	.controller('mainController', function($scope) {
		$scope.myModel = '©®';
	})
	.directive('myInput', function($timeout, $sanitize, $sce, $parse) {
	return {
    	restrict: 'EA',
        require: 'ngModel',
        scope: {
        	inputText: '=ngModel'
        },
        template: '<div>some other html here... <input ng-model="inputText"/></div>',
        link: function(scope, element, attrs, ngModel) {
            
            /*scope.$watch('inputText', function() {
               scope.$eval(attrs.ngModel + ' = inputText');
            });

            scope.$watch(attrs.ngModel, function(val) {
                scope.inputText = val;
            });*/
            
            /*scope.$watch('ngModel', function() {
            	scope.inputText = scope.ngModel;
            });*/
            console.log(element);
            
            /*ngModel.$render = function() {
              element.html('click me!! counter: ' + ngModel.$viewValue);
            };*/
            
            //format text going to user (model to view)
            ngModel.$formatters.push(function(value) {
                
                var decoded = angular.element('<div/>').html($sce.trustAsHtml(value)).text();
                console.log('formatter', value, decoded, $sce.trustAsHtml(value)); //, $parse(value));
                return decoded;//$sce.getTrustedHtml(value);
            });
            
            //format text from the user (view to model)
            ngModel.$parsers.push(function(value) {
                console.log('parser', value, $sanitize(value));
                return $sanitize(value); ///\d+/.exec(value)[0]); ///\d+/.exec(value)[0]);
            });
        }
    };
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.4/angular.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.4/angular-sanitize.js"></script>

<div ng-app="demoApp" ng-controller="mainController">
    model value = {{myModel}}<br/>
    <my-input ng-model="myModel"/>
</div>

2 个答案:

答案 0 :(得分:1)

我找到了解决办法。正如评论中提到的另一个指令它正在工作,因为ngModel可以直接处理输入元素,我认为有另一个指令可以使它工作。此外,解析器(视图模型)现在正在运行。

我仍然不确定为什么我之前的代码失败了。但我可以弄清楚以下内容:

如果ng-model指令位于模板内,格式化程序将运行两次。首先使用正确格式化的符号(©®),然后在第二次运行时将视图值设置为&copy;&reg;。这会被添加到输入字段中。 看起来像输入标签上的指令ngModel的解析器被调用并清理符号,但我不确定。

如果有人知道如何解决这个问题,请告诉我。

请查看下面或此jsfiddle中的工作代码。

angular.module('demoApp', ['ngSanitize'])
    .controller('mainController', function ($scope) {
    $scope.myModel = '&copy;&reg;';
})
    .directive('encodeEntity', function ($sanitize, $sce) {
    return {
        restrict: 'A',
        require: 'ngModel',
        link: function (scope, element, attrs, ngModel) {

            /*ngModel.$render = function () {
                //console.log(ngModel.$viewValue);
                console.log('rendered');
                element.val(ngModel.$viewValue);
            };*/

            function decode(value) {
            	return angular.element('<div/>')
                    .html($sce.trustAsHtml(value || '')).text();
            }
            //format text going to user (model to view)
            ngModel.$formatters.push(function (value) {
                var decoded = decode(value);
                console.log('formatter', value, decoded);
                return decoded;
            });

            //format text from the user (view to model)
            ngModel.$parsers.push(function (value) {
                console.log('parser', value, $sanitize(value));
                var newModelValue = $sanitize(value),
                    inputStr = '' + value,
                    startPos = inputStr.indexOf('&'),
                    last = inputStr.length - 1;
                
                if ( startPos !== -1 && inputStr[last] == ';') { 
                    console.log('update symbol');
                    ngModel.$setViewValue(decode(newModelValue));
                    ngModel.$render();
                }
                
                return newModelValue;
            });
        }
    }
})
    .directive('myInput', function () {
    return {
        restrict: 'EA',
        require: 'ngModel',
        scope: {
            inputText: '=ngModel'
        },
        //terminal: true, // terminal true deactivates any directives that are running at lower priority, e.g. an ng-model directive inside of the template
        template: '<div>Template:<input ng-model="inputText" encode-entity/></div>',
        link: function (scope, element, attrs, ngModel) {

            /* do stuff of main directiv here.... */

        }
    };
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.4/angular.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.4/angular-sanitize.js"></script>
<div ng-app="demoApp" ng-controller="mainController">model value = {{myModel}}
    <br/>
    <my-input ng-model="myModel" />
</div>

答案 1 :(得分:0)

事情是angularjs会编码你想要显示的一切。如果要显示html,可以更改代码:

<div ng-app="demoApp" ng-controller="mainController">
    model value = <span ng-bind-html="myModel"></span><br/>
    <my-input ng-model="myModel"/>
</div>

ng-bind-html期望返回的对象为:$sce.trustAsHtml

所以在你的格式化程序中:

return $sce.getTrustedHtml(value);

(不确定为何被评论出来)