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

标签 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>

最佳答案

我找到了解决方法。正如另一个指令的评论中提到的,它正在工作,因为 ngModel 可以直接在输入元素上工作,我认为可以使用另一个指令来使其工作。此外,解析器( View 到模型)现在正在工作。

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

如果 ng-model 指令位于模板内部,则格式化程序将运行两次。首先使用格式正确的符号 (©®),然后在第二次运行时将 View 值设置为 ©®。并将其添加到输入字段中。 似乎输入标记处的指令的 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>

关于javascript - 如何在自定义指令中使用 ngModel 指令的格式化程序/解析器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32150392/

相关文章:

javascript - 调用 Angular 资源后, Angular 页面未加载

javascript - 如何在 Angular 页面中设置 CSRF token - OWASP CSRFGuard 3.0

Javascript 对象未显示所有结果

angularjs - 语法错误 : Token ':' is an unexpected token when passing variable to directive

javascript - $(document).ready() 中的函数未找到 DOM 的 body 元素

javascript - 如何将两个更新请求合并为一个?

javascript - 触摸端处理程序触发两次

javascript - 使用 *ngFor 迭代 Promise<any[]>?

javascript - 缺少 ) 在使用异步等待的参数列表之后

javascript - 将下拉框选择绑定(bind)到另一个对象的 Id