为什么ng-bind-html和$ sanitize产生不同的结果?

Ami*_*ble 8 angularjs ngsanitize

我正在尝试清理某些文本区域的内容,我无法使用,ng-bind-html因为它打破了双向绑定(ng-model不能同时工作)

奇怪的是,当我应用于ng-bind-html模型时,它会在我使用$sanitize$sce在指令内部时产生不同的结果.

这是我编写的一个示例

http://plnkr.co/edit/iRvK4med8T9Xqs22BkOe?p=preview

第一个文本区域使用ng-bind-html,第二个用途$sanitize,第三个应该是ng-bind-html指令的代码,因为我从AngularJS源代码中删除了.

"只有"在使用ng-bind-html时更改为更改,在其他两个示例中更改为"

如何ng-bind-html在我的指令中复制结果- 同时保持双向绑定?

angular.module('sanitizeExample', ['ngSanitize'])
  .controller('ExampleController', ['$scope', '$sce',
    function($scope, $sce) {

      $scope.value = 'This in "quotes" for testing';
      $scope.model = 'This in "quotes" for testing';

    }
  ]).directive('sanitize', ['$sanitize', '$parse', '$sce',
    function($sanitize, $parse, $sce) {
      return {
        restrict: 'A',
        replace: true,
        scope: true,
        link: function(scope, element, attrs) {

          var process = function(input) {
            return $sanitize(input);
            //return $sce.getTrustedHtml(input);
          };

          var processed = process(scope.model);
          console.log(processed); // Output here = This in "quotes" for testing
          $parse(attrs.ngModel).assign(scope, processed);
          //element.html(processed);
        }
      };
    }
  ])
  .directive('sanitizeBindHtml', ['$parse', '$sce',
    function($parse, $sce) {
      return {
        restrict: 'A',
        replace: true,
        scope: true,
        link: function(scope, element, attrs) {

          var parsed = $parse(attrs.ngModel);

          function getStringValue() {
            var value = parsed(scope);
            getStringValue.$$unwatch = parsed.$$unwatch;
            return (value || '').toString();
          }

          scope.$watch(getStringValue, function ngBindHtmlWatchAction(value) {
            var processed = $sce.getTrustedHtml(parsed(scope)) || '';

            $parse(attrs.ngModel).assign(scope, processed)
          });
        }
      };
    }
  ]);
Run Code Online (Sandbox Code Playgroud)
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.4.3/angular.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.4.3/angular-sanitize.js"></script>

<!doctype html>
<html lang="en">


<body ng-app="sanitizeExample">

  <div ng-controller="ExampleController">
    <textarea ng-bind-html="value"></textarea>
    <br/>{{value}}
    <br/>
    <br/>
    <textarea sanitize ng-model="model"></textarea>
    <br/>
    <br/>
    <textarea sanitize-bind-html ng-model="model"></textarea>

  </div>
</body>
Run Code Online (Sandbox Code Playgroud)

Jon*_*ych 2

事实证明,正如我们所期望的那样,卫生服务返回了相同的结果。在ngBindHtmlDirective中放置一个断点,我们可以介入并查看发生了什么。我们深入研究并检查$SanitizeProvider内的值。buf将返回到 ngBindHtmlDirective的值是:

这在“引号”中是 供测试用

与我们调用 $sanitize 得到的结果完全相同,那么真正的区别是什么?真正的区别在于文本框的innerHTML 和值之间。查看这个示例 plunker。您可以看到调用两种不同方法之间的区别以及转义双引号的不同方法。我没有深入研究 w3 规范或浏览器代码,但我假设 innerHTML 分配正在创建 documentFragment 的幕后做额外的工作,获取它的 textContent,然后将其分配给文本框的值。显然,价值只是抓取字符串并按原样插入。


那么你的指令有什么问题呢?我element.html(processed)在评论中看到了这一点,但取消评论并没有影响。事实是,它确实在一瞬间起作用!使用调试器单步执行,文本框的值已正确设置,但随后 $digest 循环被触发并立即更改它!事实是 ngModelDirective 妨碍了,具体来说它是baseInputType 的 $render 函数。我们可以在代码中看到它使用了该element.val方法。

我们如何在指令中解决这个问题?需要 ngModelController 并覆盖其 $render 函数以使用element.htmlmethod 代替(例如 plunker)。

// Add require to get the controller
require: 'ngModel',

// Controller is passed in as the 4th argument
link: function(scope, element, attrs, ngModelCtrl) {

// modify the $render function to process it as HTML
ngModelCtrl.$render = function() {
    element.html(ngModelCtrl.$isEmpty(ngModelCtrl.$viewValue) ? '' : ngModelCtrl.$viewValue);
};
Run Code Online (Sandbox Code Playgroud)